2 * ionice: set or get process io scheduling class and priority
4 * Copyright (C) 2005 Jens Axboe <jens@axboe.dk>
6 * Released under the terms of the GNU General Public License version 2
14 #ifdef HAVE_SYS_SYSCALL_H
15 #include <sys/syscall.h>
22 #include "closestream.h"
26 static inline int ioprio_set(int which
, int who
, int ioprio
)
28 return syscall(SYS_ioprio_set
, which
, who
, ioprio
);
31 static inline int ioprio_get(int which
, int who
)
33 return syscall(SYS_ioprio_get
, which
, who
);
44 IOPRIO_WHO_PROCESS
= 1,
49 #define IOPRIO_CLASS_SHIFT (13)
50 #define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
52 #define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
53 #define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
54 #define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
56 static const char *to_prio
[] = {
57 [IOPRIO_CLASS_NONE
] = "none",
58 [IOPRIO_CLASS_RT
] = "realtime",
59 [IOPRIO_CLASS_BE
] = "best-effort",
60 [IOPRIO_CLASS_IDLE
] = "idle"
63 static int parse_ioclass(const char *str
)
67 for (i
= 0; i
< ARRAY_SIZE(to_prio
); i
++)
68 if (!strcasecmp(str
, to_prio
[i
]))
73 static void ioprio_print(int pid
, int who
)
75 int ioprio
= ioprio_get(who
, pid
);
78 err(EXIT_FAILURE
, _("ioprio_get failed"));
80 int ioclass
= IOPRIO_PRIO_CLASS(ioprio
);
81 const char *name
= _("unknown");
83 if (ioclass
>= 0 && (size_t) ioclass
< ARRAY_SIZE(to_prio
))
84 name
= to_prio
[ioclass
];
86 if (ioclass
!= IOPRIO_CLASS_IDLE
)
87 printf(_("%s: prio %lu\n"), name
,
88 IOPRIO_PRIO_DATA(ioprio
));
94 static void ioprio_setid(int which
, int ioclass
, int data
, int who
)
96 int rc
= ioprio_set(who
, which
,
97 IOPRIO_PRIO_VALUE(ioclass
, data
));
99 if (rc
== -1 && !tolerant
)
100 err(EXIT_FAILURE
, _("ioprio_set failed"));
103 static void __attribute__((__noreturn__
)) usage(void)
106 fputs(USAGE_HEADER
, out
);
107 fprintf(out
, _(" %1$s [options] -p <pid>...\n"
108 " %1$s [options] -P <pgid>...\n"
109 " %1$s [options] -u <uid>...\n"
110 " %1$s [options] <command>\n"), program_invocation_short_name
);
112 fputs(USAGE_SEPARATOR
, out
);
113 fputs(_("Show or change the I/O-scheduling class and priority of a process.\n"), out
);
115 fputs(USAGE_OPTIONS
, out
);
116 fputs(_(" -c, --class <class> name or number of scheduling class,\n"
117 " 0: none, 1: realtime, 2: best-effort, 3: idle\n"), out
);
118 fputs(_(" -n, --classdata <num> priority (0..7) in the specified scheduling class,\n"
119 " only for the realtime and best-effort classes\n"), out
);
120 fputs(_(" -p, --pid <pid>... act on these already running processes\n"), out
);
121 fputs(_(" -P, --pgid <pgrp>... act on already running processes in these groups\n"), out
);
122 fputs(_(" -t, --ignore ignore failures\n"), out
);
123 fputs(_(" -u, --uid <uid>... act on already running processes owned by these users\n"), out
);
125 fputs(USAGE_SEPARATOR
, out
);
126 printf(USAGE_HELP_OPTIONS(24));
128 printf(USAGE_MAN_TAIL("ionice(1)"));
133 int main(int argc
, char **argv
)
135 int data
= 4, set
= 0, ioclass
= IOPRIO_CLASS_BE
, c
;
136 int which
= 0, who
= 0;
137 const char *invalid_msg
= NULL
;
139 static const struct option longopts
[] = {
140 { "classdata", required_argument
, NULL
, 'n' },
141 { "class", required_argument
, NULL
, 'c' },
142 { "help", no_argument
, NULL
, 'h' },
143 { "ignore", no_argument
, NULL
, 't' },
144 { "pid", required_argument
, NULL
, 'p' },
145 { "pgid", required_argument
, NULL
, 'P' },
146 { "uid", required_argument
, NULL
, 'u' },
147 { "version", no_argument
, NULL
, 'V' },
151 setlocale(LC_ALL
, "");
152 bindtextdomain(PACKAGE
, LOCALEDIR
);
154 close_stdout_atexit();
156 while ((c
= getopt_long(argc
, argv
, "+n:c:p:P:u:tVh", longopts
, NULL
)) != EOF
)
159 data
= strtos32_or_err(optarg
, _("invalid class data argument"));
163 if (isdigit(*optarg
))
164 ioclass
= strtos32_or_err(optarg
,
165 _("invalid class argument"));
167 ioclass
= parse_ioclass(optarg
);
170 _("unknown scheduling class: '%s'"),
178 _("can handle only one of pid, pgid or uid at once"));
179 invalid_msg
= _("invalid PID argument");
180 which
= strtos32_or_err(optarg
, invalid_msg
);
181 who
= IOPRIO_WHO_PROCESS
;
186 _("can handle only one of pid, pgid or uid at once"));
187 invalid_msg
= _("invalid PGID argument");
188 which
= strtos32_or_err(optarg
, invalid_msg
);
189 who
= IOPRIO_WHO_PGRP
;
194 _("can handle only one of pid, pgid or uid at once"));
195 invalid_msg
= _("invalid UID argument");
196 which
= strtos32_or_err(optarg
, invalid_msg
);
197 who
= IOPRIO_WHO_USER
;
204 print_version(EXIT_SUCCESS
);
208 errtryhelp(EXIT_FAILURE
);
212 case IOPRIO_CLASS_NONE
:
213 if ((set
& 1) && !tolerant
)
214 warnx(_("ignoring given class data for none class"));
217 case IOPRIO_CLASS_RT
:
218 case IOPRIO_CLASS_BE
:
220 case IOPRIO_CLASS_IDLE
:
221 if ((set
& 1) && !tolerant
)
222 warnx(_("ignoring given class data for idle class"));
227 warnx(_("unknown prio class %d"), ioclass
);
231 if (!set
&& !which
&& optind
== argc
)
233 * ionice without options, print the current ioprio
235 ioprio_print(0, IOPRIO_WHO_PROCESS
);
236 else if (!set
&& who
) {
238 * ionice -p|-P|-u ID [ID ...]
240 ioprio_print(which
, who
);
242 for(; argv
[optind
]; ++optind
) {
243 which
= strtos32_or_err(argv
[optind
], invalid_msg
);
244 ioprio_print(which
, who
);
246 } else if (set
&& who
) {
248 * ionice -c CLASS -p|-P|-u ID [ID ...]
250 ioprio_setid(which
, ioclass
, data
, who
);
252 for(; argv
[optind
]; ++optind
) {
253 which
= strtos32_or_err(argv
[optind
], invalid_msg
);
254 ioprio_setid(which
, ioclass
, data
, who
);
256 } else if (argv
[optind
]) {
258 * ionice [-c CLASS] COMMAND
260 ioprio_setid(0, ioclass
, data
, IOPRIO_WHO_PROCESS
);
261 execvp(argv
[optind
], &argv
[optind
]);
262 errexec(argv
[optind
]);
264 warnx(_("bad usage"));
265 errtryhelp(EXIT_FAILURE
);