LCOV - code coverage report
Current view: top level - block - ioprio.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 14 134 10.4 %
Date: 2022-03-28 15:32:58 Functions: 1 10 10.0 %
Branches: 4 127 3.1 %

           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                 :         84 : int set_task_ioprio(struct task_struct *task, int ioprio)
      37                 :            : {
      38                 :         84 :         int err;
      39                 :         84 :         struct io_context *ioc;
      40                 :         84 :         const struct cred *cred = current_cred(), *tcred;
      41                 :            : 
      42                 :         84 :         rcu_read_lock();
      43         [ -  + ]:         84 :         tcred = __task_cred(task);
      44   [ -  +  -  - ]:         84 :         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                 :         84 :         rcu_read_unlock();
      50                 :            : 
      51                 :         84 :         err = security_task_setioprio(task, ioprio);
      52         [ +  - ]:         84 :         if (err)
      53                 :            :                 return err;
      54                 :            : 
      55                 :         84 :         ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE);
      56         [ +  - ]:         84 :         if (ioc) {
      57                 :         84 :                 ioc->ioprio = ioprio;
      58                 :         84 :                 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                 :            : }

Generated by: LCOV version 1.14