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 : 3 : int set_task_ioprio(struct task_struct *task, int ioprio) 37 : : { 38 : : int err; 39 : : struct io_context *ioc; 40 : 3 : const struct cred *cred = current_cred(), *tcred; 41 : : 42 : : rcu_read_lock(); 43 : 3 : tcred = __task_cred(task); 44 : 3 : if (!uid_eq(tcred->uid, cred->euid) && 45 : 0 : !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) { 46 : : rcu_read_unlock(); 47 : 0 : return -EPERM; 48 : : } 49 : : rcu_read_unlock(); 50 : : 51 : 3 : err = security_task_setioprio(task, ioprio); 52 : 3 : if (err) 53 : : return err; 54 : : 55 : 3 : ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); 56 : 3 : if (ioc) { 57 : 3 : ioc->ioprio = ioprio; 58 : 3 : put_io_context(ioc); 59 : : } 60 : : 61 : 3 : return err; 62 : : } 63 : : EXPORT_SYMBOL_GPL(set_task_ioprio); 64 : : 65 : 3 : int ioprio_check_cap(int ioprio) 66 : : { 67 : 3 : int class = IOPRIO_PRIO_CLASS(ioprio); 68 : 3 : int data = IOPRIO_PRIO_DATA(ioprio); 69 : : 70 : 3 : switch (class) { 71 : : 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 : 3 : if (data >= IOPRIO_BE_NR || data < 0) 78 : : return -EINVAL; 79 : : 80 : : break; 81 : : case IOPRIO_CLASS_IDLE: 82 : : break; 83 : : case IOPRIO_CLASS_NONE: 84 : 0 : if (data) 85 : : return -EINVAL; 86 : : break; 87 : : default: 88 : : return -EINVAL; 89 : : } 90 : : 91 : : return 0; 92 : : } 93 : : 94 : 3 : SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) 95 : : { 96 : : struct task_struct *p, *g; 97 : : struct user_struct *user; 98 : : struct pid *pgrp; 99 : : kuid_t uid; 100 : : int ret; 101 : : 102 : 3 : ret = ioprio_check_cap(ioprio); 103 : 3 : if (ret) 104 : : return ret; 105 : : 106 : : ret = -ESRCH; 107 : : rcu_read_lock(); 108 : 3 : switch (which) { 109 : : case IOPRIO_WHO_PROCESS: 110 : 3 : if (!who) 111 : 3 : p = current; 112 : : else 113 : 0 : p = find_task_by_vpid(who); 114 : 3 : if (p) 115 : 3 : ret = set_task_ioprio(p, ioprio); 116 : : break; 117 : : 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 : : } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); 127 : : break; 128 : : 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 : : goto free_uid; 147 : : } 148 : : free_uid: 149 : 0 : if (who) 150 : 0 : free_uid(user); 151 : : break; 152 : : default: 153 : : ret = -EINVAL; 154 : : } 155 : : 156 : : rcu_read_unlock(); 157 : 3 : return ret; 158 : : } 159 : : 160 : 3 : static int get_task_ioprio(struct task_struct *p) 161 : : { 162 : : int ret; 163 : : 164 : 3 : ret = security_task_getioprio(p); 165 : 3 : if (ret) 166 : : goto out; 167 : : ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); 168 : : task_lock(p); 169 : 3 : if (p->io_context) 170 : 3 : ret = p->io_context->ioprio; 171 : : task_unlock(p); 172 : : out: 173 : 3 : return ret; 174 : : } 175 : : 176 : 0 : int ioprio_best(unsigned short aprio, unsigned short bprio) 177 : : { 178 : 0 : if (!ioprio_valid(aprio)) 179 : : aprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); 180 : 0 : if (!ioprio_valid(bprio)) 181 : : bprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); 182 : : 183 : 0 : return min(aprio, bprio); 184 : : } 185 : : 186 : 3 : SYSCALL_DEFINE2(ioprio_get, int, which, int, who) 187 : : { 188 : : struct task_struct *g, *p; 189 : : struct user_struct *user; 190 : : struct pid *pgrp; 191 : : kuid_t uid; 192 : : int ret = -ESRCH; 193 : : int tmpio; 194 : : 195 : : rcu_read_lock(); 196 : 3 : switch (which) { 197 : : case IOPRIO_WHO_PROCESS: 198 : 3 : if (!who) 199 : 3 : p = current; 200 : : else 201 : 0 : p = find_task_by_vpid(who); 202 : 3 : if (p) 203 : 3 : ret = get_task_ioprio(p); 204 : : break; 205 : : 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 : : } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); 219 : : break; 220 : : 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 : : rcu_read_unlock(); 251 : 3 : return ret; 252 : : }