LCOV - code coverage report
Current view: top level - block - ioprio.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 65 137 47.4 %
Date: 2021-04-22 12:43:58 Functions: 7 10 70.0 %

          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           6 : int set_task_ioprio(struct task_struct *task, int ioprio)
      37             : {
      38           6 :         int err;
      39           6 :         struct io_context *ioc;
      40           6 :         const struct cred *cred = current_cred(), *tcred;
      41             : 
      42           6 :         rcu_read_lock();
      43           6 :         tcred = __task_cred(task);
      44           6 :         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           6 :         rcu_read_unlock();
      50             : 
      51           6 :         err = security_task_setioprio(task, ioprio);
      52           6 :         if (err)
      53             :                 return err;
      54             : 
      55           6 :         ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE);
      56           6 :         if (ioc) {
      57           6 :                 ioc->ioprio = ioprio;
      58           6 :                 put_io_context(ioc);
      59             :         }
      60             : 
      61             :         return err;
      62             : }
      63             : EXPORT_SYMBOL_GPL(set_task_ioprio);
      64             : 
      65           4 : int ioprio_check_cap(int ioprio)
      66             : {
      67           4 :         int class = IOPRIO_PRIO_CLASS(ioprio);
      68           4 :         int data = IOPRIO_PRIO_DATA(ioprio);
      69             : 
      70           4 :         switch (class) {
      71           0 :                 case IOPRIO_CLASS_RT:
      72           0 :                         if (!capable(CAP_SYS_NICE) && !capable(CAP_SYS_ADMIN))
      73             :                                 return -EPERM;
      74           1 :                         fallthrough;
      75             :                         /* rt has prio field too */
      76             :                 case IOPRIO_CLASS_BE:
      77           1 :                         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           8 : SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
      95             : {
      96           4 :         struct task_struct *p, *g;
      97           4 :         struct user_struct *user;
      98           4 :         struct pid *pgrp;
      99           4 :         kuid_t uid;
     100           4 :         int ret;
     101             : 
     102           4 :         ret = ioprio_check_cap(ioprio);
     103           4 :         if (ret)
     104           0 :                 return ret;
     105             : 
     106           4 :         ret = -ESRCH;
     107           4 :         rcu_read_lock();
     108           4 :         switch (which) {
     109           4 :                 case IOPRIO_WHO_PROCESS:
     110           4 :                         if (!who)
     111           4 :                                 p = current;
     112             :                         else
     113           0 :                                 p = find_task_by_vpid(who);
     114           4 :                         if (p)
     115           4 :                                 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           0 :                                     !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           4 :         rcu_read_unlock();
     157           4 :         return ret;
     158             : }
     159             : 
     160           2 : static int get_task_ioprio(struct task_struct *p)
     161             : {
     162           2 :         int ret;
     163             : 
     164           2 :         ret = security_task_getioprio(p);
     165           2 :         if (ret)
     166           0 :                 goto out;
     167           2 :         ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM);
     168           2 :         task_lock(p);
     169           2 :         if (p->io_context)
     170           2 :                 ret = p->io_context->ioprio;
     171           2 :         task_unlock(p);
     172           2 : out:
     173           2 :         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           4 : SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
     187             : {
     188           2 :         struct task_struct *g, *p;
     189           2 :         struct user_struct *user;
     190           2 :         struct pid *pgrp;
     191           2 :         kuid_t uid;
     192           2 :         int ret = -ESRCH;
     193           2 :         int tmpio;
     194             : 
     195           2 :         rcu_read_lock();
     196           2 :         switch (which) {
     197           2 :                 case IOPRIO_WHO_PROCESS:
     198           2 :                         if (!who)
     199           2 :                                 p = current;
     200             :                         else
     201           0 :                                 p = find_task_by_vpid(who);
     202           2 :                         if (p)
     203           2 :                                 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           0 :                                     !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           2 :         rcu_read_unlock();
     251           2 :         return ret;
     252             : }

Generated by: LCOV version 1.14