Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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/gfp.h>
 23#include <linux/kernel.h>
 24#include <linux/ioprio.h>
 25#include <linux/blkdev.h>
 26#include <linux/capability.h>
 27#include <linux/syscalls.h>
 28#include <linux/security.h>
 29#include <linux/pid_namespace.h>
 30
 31int set_task_ioprio(struct task_struct *task, int ioprio)
 32{
 33	int err;
 34	struct io_context *ioc;
 35	const struct cred *cred = current_cred(), *tcred;
 36
 37	rcu_read_lock();
 38	tcred = __task_cred(task);
 39	if (tcred->uid != cred->euid &&
 40	    tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
 41		rcu_read_unlock();
 42		return -EPERM;
 43	}
 44	rcu_read_unlock();
 45
 46	err = security_task_setioprio(task, ioprio);
 47	if (err)
 48		return err;
 49
 50	task_lock(task);
 51	do {
 52		ioc = task->io_context;
 53		/* see wmb() in current_io_context() */
 54		smp_read_barrier_depends();
 55		if (ioc)
 56			break;
 57
 58		ioc = alloc_io_context(GFP_ATOMIC, -1);
 59		if (!ioc) {
 60			err = -ENOMEM;
 61			break;
 62		}
 63		task->io_context = ioc;
 64	} while (1);
 65
 66	if (!err) {
 67		ioc->ioprio = ioprio;
 68		ioc->ioprio_changed = 1;
 69	}
 70
 71	task_unlock(task);
 72	return err;
 73}
 74EXPORT_SYMBOL_GPL(set_task_ioprio);
 75
 76SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
 77{
 78	int class = IOPRIO_PRIO_CLASS(ioprio);
 79	int data = IOPRIO_PRIO_DATA(ioprio);
 80	struct task_struct *p, *g;
 81	struct user_struct *user;
 82	struct pid *pgrp;
 83	int ret;
 84
 85	switch (class) {
 86		case IOPRIO_CLASS_RT:
 87			if (!capable(CAP_SYS_ADMIN))
 88				return -EPERM;
 89			/* fall through, rt has prio field too */
 90		case IOPRIO_CLASS_BE:
 91			if (data >= IOPRIO_BE_NR || data < 0)
 92				return -EINVAL;
 93
 94			break;
 95		case IOPRIO_CLASS_IDLE:
 96			break;
 97		case IOPRIO_CLASS_NONE:
 98			if (data)
 99				return -EINVAL;
100			break;
101		default:
102			return -EINVAL;
103	}
104
105	ret = -ESRCH;
106	rcu_read_lock();
107	switch (which) {
108		case IOPRIO_WHO_PROCESS:
109			if (!who)
110				p = current;
111			else
112				p = find_task_by_vpid(who);
113			if (p)
114				ret = set_task_ioprio(p, ioprio);
115			break;
116		case IOPRIO_WHO_PGRP:
117			if (!who)
118				pgrp = task_pgrp(current);
119			else
120				pgrp = find_vpid(who);
121			do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
122				ret = set_task_ioprio(p, ioprio);
123				if (ret)
124					break;
125			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
126			break;
127		case IOPRIO_WHO_USER:
128			if (!who)
129				user = current_user();
130			else
131				user = find_user(who);
132
133			if (!user)
134				break;
135
136			do_each_thread(g, p) {
137				if (__task_cred(p)->uid != who)
138					continue;
139				ret = set_task_ioprio(p, ioprio);
140				if (ret)
141					goto free_uid;
142			} while_each_thread(g, p);
143free_uid:
144			if (who)
145				free_uid(user);
146			break;
147		default:
148			ret = -EINVAL;
149	}
150
151	rcu_read_unlock();
152	return ret;
153}
154
155static int get_task_ioprio(struct task_struct *p)
156{
157	int ret;
158
159	ret = security_task_getioprio(p);
160	if (ret)
161		goto out;
162	ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
163	if (p->io_context)
164		ret = p->io_context->ioprio;
165out:
166	return ret;
167}
168
169int ioprio_best(unsigned short aprio, unsigned short bprio)
170{
171	unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
172	unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
173
174	if (aclass == IOPRIO_CLASS_NONE)
175		aclass = IOPRIO_CLASS_BE;
176	if (bclass == IOPRIO_CLASS_NONE)
177		bclass = IOPRIO_CLASS_BE;
178
179	if (aclass == bclass)
180		return min(aprio, bprio);
181	if (aclass > bclass)
182		return bprio;
183	else
184		return aprio;
185}
186
187SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
188{
189	struct task_struct *g, *p;
190	struct user_struct *user;
191	struct pid *pgrp;
192	int ret = -ESRCH;
193	int tmpio;
194
195	rcu_read_lock();
196	switch (which) {
197		case IOPRIO_WHO_PROCESS:
198			if (!who)
199				p = current;
200			else
201				p = find_task_by_vpid(who);
202			if (p)
203				ret = get_task_ioprio(p);
204			break;
205		case IOPRIO_WHO_PGRP:
206			if (!who)
207				pgrp = task_pgrp(current);
208			else
209				pgrp = find_vpid(who);
210			do_each_pid_thread(pgrp, PIDTYPE_PGID, p) {
211				tmpio = get_task_ioprio(p);
212				if (tmpio < 0)
213					continue;
214				if (ret == -ESRCH)
215					ret = tmpio;
216				else
217					ret = ioprio_best(ret, tmpio);
218			} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
219			break;
220		case IOPRIO_WHO_USER:
221			if (!who)
222				user = current_user();
223			else
224				user = find_user(who);
225
226			if (!user)
227				break;
228
229			do_each_thread(g, p) {
230				if (__task_cred(p)->uid != user->uid)
231					continue;
232				tmpio = get_task_ioprio(p);
233				if (tmpio < 0)
234					continue;
235				if (ret == -ESRCH)
236					ret = tmpio;
237				else
238					ret = ioprio_best(ret, tmpio);
239			} while_each_thread(g, p);
240
241			if (who)
242				free_uid(user);
243			break;
244		default:
245			ret = -EINVAL;
246	}
247
248	rcu_read_unlock();
249	return ret;
250}