diff options
-rw-r--r-- | ChangeLog | 23 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | debian/changelog | 3 | ||||
-rw-r--r-- | man/start-stop-daemon.8 | 7 | ||||
-rw-r--r-- | utils/start-stop-daemon.c | 98 |
5 files changed, 132 insertions, 2 deletions
@@ -1,3 +1,26 @@ +2009-02-26 Chris Coulson <chrisccoulson@googlemail.com>, + Guillem Jover <guillem@debian.org> + + * configure.ac (AC_CHECK_HEADERS): Add 'sys/syscall.h'. + * man/start-stop-daemon.8: Document new option --iosched. + * utils/start-stop-daemon.c [HAVE_SYS_SYSCALL_H]: Include + <sys/syscall.h>. + (HAVE_IOPRIO_SET) [SYS_ioprio_set, linux]: New macro. + (IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT): New anonymous enum. + (IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE): Likewise. + (IOPRIO_WHO_PROCESS, IOPRIO_WHO_PGRP, IOPRIO_WHO_USER): Likewise. + (IOPRIO_CLASS_SHIFT, IOPRIO_PRIO_VALUE, IO_SCHED_PRIO_MIN) + (IO_SCHED_PRIO_MAX): New macros. + (io_sched): New variable. + (do_help): Document --iosched. + (ioprio_set) [HAVE_IOPRIO_SET]: New function. + (parse_io_schedule, set_io_schedule): Likewise. + (parse_options): Add 'iosched' to longopts. Add 'I:' to getopt_long + call. Handle 'I' as getopt_long return value. Call parse_io_schedule + if io_schedule_str is not NULL. + (main): Print io_sched values if --test is used. Call set_io_schedule + if io_sched is not NULL. + 2009-02-26 Romain Francoise <rfrancoise@debian.org>, Guillem Jover <guillem@debian.org> diff --git a/configure.ac b/configure.ac index 53694ca0b..3d3b60743 100644 --- a/configure.ac +++ b/configure.ac @@ -73,7 +73,8 @@ fi # Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS([stddef.h error.h locale.h libintl.h sys/cdefs.h kvm.h]) +AC_CHECK_HEADERS([stddef.h error.h locale.h libintl.h kvm.h \ + sys/cdefs.h sys/syscall.h]) DPKG_CHECK_DEFINE(TIOCNOTTY, [sys/ioctl.h]) # Checks for typedefs, structures, and compiler characteristics. diff --git a/debian/changelog b/debian/changelog index 4d7610030..67128bda5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -62,6 +62,9 @@ dpkg (1.15.0) UNRELEASED; urgency=low * Print correct feature name on «dpkg --assert-*» failures. * Add progress reporting to dpkg while reading the file list database. Based on a patch by Romain Francoise. + * Add new option --iosched to start-stop-daemon to be able to set the + IO scheduling class and priority. Closes: #443535 + Thanks to Chris Coulson <chrisccoulson@googlemail.com>. [ Raphael Hertzog ] * Enhance dpkg-shlibdeps's error message when a library can't be found to diff --git a/man/start-stop-daemon.8 b/man/start-stop-daemon.8 index 26996b941..1e6c00f07 100644 --- a/man/start-stop-daemon.8 +++ b/man/start-stop-daemon.8 @@ -225,6 +225,13 @@ starting it. The priority can be optionally specified by appending a \fB:\fP followed by the value. The default \fIpriority\fP is 0. The currently supported policy values are \fBother\fP, \fBfifo\fP and \fBrr\fP. .TP +.BR \-I ", " \-\-iosched " \fIclass\fP\fB:\fP\fIpriority\fP" +This alters the IO scheduler class and priority of the process before starting +it. The priority can be optionally specified by appending a \fB:\fP followed +by the value. The default \fIpriority\fP is 4, unless \fIclass\fP is \fBidle\fP, +then \fIpriority\fP will always be 7. The currently supported values for +\fIclass\fP are \fBidle\fP, \fBbest-effort\fP and \fBreal-time\fP. +.TP .BR \-k ", " \-\-umask " \fImask\fP" This sets the umask of the process before starting it. .TP diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c index 8171dc3d4..34ee0221d 100644 --- a/utils/start-stop-daemon.c +++ b/utils/start-stop-daemon.c @@ -111,6 +111,27 @@ #include <error.h> #endif +#ifdef HAVE_SYS_SYSCALL_H +#include <sys/syscall.h> +#endif + +#if defined(SYS_ioprio_set) && defined(linux) +#define HAVE_IOPRIO_SET +#endif + +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, +}; + +enum { + IOPRIO_CLASS_NONE, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + static int testmode = 0; static int quietmode = 0; static int exitnodo = 1; @@ -136,6 +157,11 @@ static const char *progname = ""; static int nicelevel = 0; static int umask_value = -1; +#define IOPRIO_CLASS_SHIFT 13 +#define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio)) +#define IO_SCHED_PRIO_MIN 0 +#define IO_SCHED_PRIO_MAX 7 + static struct stat exec_stat; #if defined(OSHURD) static struct proc_stat_list *procset = NULL; @@ -168,6 +194,7 @@ struct schedule_item { }; static struct res_schedule *proc_sched = NULL; +static struct res_schedule *io_sched = NULL; static int schedule_length; static struct schedule_item *schedule = NULL; @@ -339,6 +366,8 @@ do_help(void) " -P|--procsched <policy[:prio]>\n" " use <policy> with <prio> for the kernel\n" " process scheduler (default prio is 0)\n" +" -I|--iosched <class[:prio]> use <class> with <prio> to set the IO\n" +" scheduler (default prio is 4)\n" " -k|--umask <mask> change the umask to <mask> before starting\n" " -b|--background force the process to detach\n" " -m|--make-pidfile create the pidfile before starting\n" @@ -493,6 +522,40 @@ parse_proc_schedule(const char *string) } static void +parse_io_schedule(const char *string) +{ + char *class_str, *prio_str; + int prio = 4; + + class_str = xstrdup(string); + class_str = strtok(class_str, ":"); + prio_str = strtok(NULL, ":"); + + if (prio_str && parse_integer(prio_str, &prio) != 0) + fatal("invalid IO scheduler priority"); + + io_sched = xmalloc(sizeof(*io_sched)); + io_sched->policy_name = class_str; + + if (strcmp(class_str, "real-time") == 0) { + io_sched->policy = IOPRIO_CLASS_RT; + io_sched->priority = prio; + } else if (strcmp(class_str, "best-effort") == 0) { + io_sched->policy = IOPRIO_CLASS_BE; + io_sched->priority = prio; + } else if (strcmp(class_str, "idle") == 0) { + io_sched->policy = IOPRIO_CLASS_IDLE; + io_sched->priority = 7; + } else + badusage("invalid IO scheduler policy"); + + if (io_sched->priority < IO_SCHED_PRIO_MIN) + badusage("IO scheduler priority less than min"); + if (io_sched->priority > IO_SCHED_PRIO_MAX) + badusage("IO scheduler priority greater than max"); +} + +static void set_proc_schedule(struct res_schedule *sched) { #ifdef _POSIX_PRIORITY_SCHEDULING @@ -505,6 +568,26 @@ set_proc_schedule(struct res_schedule *sched) #endif } +#ifdef HAVE_IOPRIO_SET +static inline int +ioprio_set(int which, int who, int ioprio) +{ + return syscall(SYS_ioprio_set, which, who, ioprio); +} +#endif + +static void +set_io_schedule(struct res_schedule *sched) +{ +#ifdef HAVE_IOPRIO_SET + int io_sched_mask; + + io_sched_mask = IOPRIO_PRIO_VALUE(sched->policy, sched->priority); + if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), io_sched_mask) == -1) + fatal("Unable to alter IO priority to mask %i", io_sched_mask); +#endif +} + static void parse_schedule_item(const char *string, struct schedule_item *item) { @@ -607,6 +690,7 @@ parse_options(int argc, char * const *argv) { "chuid", 1, NULL, 'c'}, { "nicelevel", 1, NULL, 'N'}, { "procsched", 1, NULL, 'P'}, + { "iosched", 1, NULL, 'I'}, { "umask", 1, NULL, 'k'}, { "background", 0, NULL, 'b'}, { "make-pidfile", 0, NULL, 'm'}, @@ -618,11 +702,12 @@ parse_options(int argc, char * const *argv) const char *signal_str = NULL; const char *schedule_str = NULL; const char *proc_schedule_str = NULL; + const char *io_schedule_str = NULL; int c; for (;;) { c = getopt_long(argc, argv, - "HKSVa:n:op:qr:s:tu:vx:c:N:P:k:bmR:g:d:", + "HKSVa:n:op:qr:s:tu:vx:c:N:P:I:k:bmR:g:d:", longopts, NULL); if (c == -1) break; @@ -688,6 +773,9 @@ parse_options(int argc, char * const *argv) case 'P': /* --procsched */ proc_schedule_str = optarg; break; + case 'I': /* --iosched */ + io_schedule_str = optarg; + break; case 'k': /* --umask <mask> */ umask_str = optarg; break; @@ -721,6 +809,9 @@ parse_options(int argc, char * const *argv) if (proc_schedule_str != NULL) parse_proc_schedule(proc_schedule_str); + if (io_schedule_str != NULL) + parse_io_schedule(io_schedule_str); + if (umask_str != NULL) { if (parse_umask(umask_str, &umask_value) != 0) badusage("umask value must be a positive number"); @@ -1410,6 +1501,9 @@ main(int argc, char **argv) if (proc_sched) printf(", with scheduling policy %s with priority %i", proc_sched->policy_name, proc_sched->priority); + if (io_sched) + printf(", with IO scheduling class %s with priority %i", + io_sched->policy_name, io_sched->priority); printf(".\n"); } if (testmode) @@ -1433,6 +1527,8 @@ main(int argc, char **argv) } if (proc_sched) set_proc_schedule(proc_sched); + if (io_sched) + set_io_schedule(io_sched); if (umask_value >= 0) umask(umask_value); if (mpidfile && pidfile != NULL) { |