]> err.no Git - linux-2.6/blob - fs/ioprio.c
io context sharing: preliminary support
[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                         if (!capable(CAP_SYS_ADMIN))
89                                 return -EPERM;
90                         break;
91                 case IOPRIO_CLASS_NONE:
92                         if (data)
93                                 return -EINVAL;
94                         break;
95                 default:
96                         return -EINVAL;
97         }
98
99         ret = -ESRCH;
100         /*
101          * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
102          * so we can't use rcu_read_lock(). See re-copy of ->ioprio
103          * in copy_process().
104          */
105         read_lock(&tasklist_lock);
106         switch (which) {
107                 case IOPRIO_WHO_PROCESS:
108                         if (!who)
109                                 p = current;
110                         else
111                                 p = find_task_by_vpid(who);
112                         if (p)
113                                 ret = set_task_ioprio(p, ioprio);
114                         break;
115                 case IOPRIO_WHO_PGRP:
116                         if (!who)
117                                 pgrp = task_pgrp(current);
118                         else
119                                 pgrp = find_vpid(who);
120                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
121                                 ret = set_task_ioprio(p, ioprio);
122                                 if (ret)
123                                         break;
124                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
125                         break;
126                 case IOPRIO_WHO_USER:
127                         if (!who)
128                                 user = current->user;
129                         else
130                                 user = find_user(who);
131
132                         if (!user)
133                                 break;
134
135                         do_each_thread(g, p) {
136                                 if (p->uid != who)
137                                         continue;
138                                 ret = set_task_ioprio(p, ioprio);
139                                 if (ret)
140                                         goto free_uid;
141                         } while_each_thread(g, p);
142 free_uid:
143                         if (who)
144                                 free_uid(user);
145                         break;
146                 default:
147                         ret = -EINVAL;
148         }
149
150         read_unlock(&tasklist_lock);
151         return ret;
152 }
153
154 static int get_task_ioprio(struct task_struct *p)
155 {
156         int ret;
157
158         ret = security_task_getioprio(p);
159         if (ret)
160                 goto out;
161         ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
162         if (p->io_context)
163                 ret = p->io_context->ioprio;
164 out:
165         return ret;
166 }
167
168 int ioprio_best(unsigned short aprio, unsigned short bprio)
169 {
170         unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
171         unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
172
173         if (aclass == IOPRIO_CLASS_NONE)
174                 aclass = IOPRIO_CLASS_BE;
175         if (bclass == IOPRIO_CLASS_NONE)
176                 bclass = IOPRIO_CLASS_BE;
177
178         if (aclass == bclass)
179                 return min(aprio, bprio);
180         if (aclass > bclass)
181                 return bprio;
182         else
183                 return aprio;
184 }
185
186 asmlinkage long sys_ioprio_get(int which, int who)
187 {
188         struct task_struct *g, *p;
189         struct user_struct *user;
190         struct pid *pgrp;
191         int ret = -ESRCH;
192         int tmpio;
193
194         read_lock(&tasklist_lock);
195         switch (which) {
196                 case IOPRIO_WHO_PROCESS:
197                         if (!who)
198                                 p = current;
199                         else
200                                 p = find_task_by_vpid(who);
201                         if (p)
202                                 ret = get_task_ioprio(p);
203                         break;
204                 case IOPRIO_WHO_PGRP:
205                         if (!who)
206                                 pgrp = task_pgrp(current);
207                         else
208                                 pgrp = find_vpid(who);
209                         do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
210                                 tmpio = get_task_ioprio(p);
211                                 if (tmpio < 0)
212                                         continue;
213                                 if (ret == -ESRCH)
214                                         ret = tmpio;
215                                 else
216                                         ret = ioprio_best(ret, tmpio);
217                         } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
218                         break;
219                 case IOPRIO_WHO_USER:
220                         if (!who)
221                                 user = current->user;
222                         else
223                                 user = find_user(who);
224
225                         if (!user)
226                                 break;
227
228                         do_each_thread(g, p) {
229                                 if (p->uid != user->uid)
230                                         continue;
231                                 tmpio = get_task_ioprio(p);
232                                 if (tmpio < 0)
233                                         continue;
234                                 if (ret == -ESRCH)
235                                         ret = tmpio;
236                                 else
237                                         ret = ioprio_best(ret, tmpio);
238                         } while_each_thread(g, p);
239
240                         if (who)
241                                 free_uid(user);
242                         break;
243                 default:
244                         ret = -EINVAL;
245         }
246
247         read_unlock(&tasklist_lock);
248         return ret;
249 }
250