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