Просмотр исходного кода

s-s-d: Support setting the IO scheduler class and priority

Add new option -I, --iosched <class[:priority]>.

Closes: #443535

Signed-off-by: Guillem Jover <guillem@debian.org>
Chris Coulson лет назад: 17
Родитель
Сommit
b0569c7d4d
5 измененных файлов с 132 добавлено и 2 удалено
  1. 23 0
      ChangeLog
  2. 2 1
      configure.ac
  3. 3 0
      debian/changelog
  4. 7 0
      man/start-stop-daemon.8
  5. 97 1
      utils/start-stop-daemon.c

+ 23 - 0
ChangeLog

@@ -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>,
 2009-02-26  Romain Francoise <rfrancoise@debian.org>,
             Guillem Jover  <guillem@debian.org>
             Guillem Jover  <guillem@debian.org>
 
 

+ 2 - 1
configure.ac

@@ -73,7 +73,8 @@ fi
 
 
 # Checks for header files.
 # Checks for header files.
 AC_HEADER_STDC
 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])
 DPKG_CHECK_DEFINE(TIOCNOTTY, [sys/ioctl.h])
 
 
 # Checks for typedefs, structures, and compiler characteristics.
 # Checks for typedefs, structures, and compiler characteristics.

+ 3 - 0
debian/changelog

@@ -62,6 +62,9 @@ dpkg (1.15.0) UNRELEASED; urgency=low
   * Print correct feature name on «dpkg --assert-*» failures.
   * Print correct feature name on «dpkg --assert-*» failures.
   * Add progress reporting to dpkg while reading the file list database.
   * Add progress reporting to dpkg while reading the file list database.
     Based on a patch by Romain Francoise.
     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 ]
   [ Raphael Hertzog ]
   * Enhance dpkg-shlibdeps's error message when a library can't be found to
   * Enhance dpkg-shlibdeps's error message when a library can't be found to

+ 7 - 0
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
 followed by the value. The default \fIpriority\fP is 0. The currently
 supported policy values are \fBother\fP, \fBfifo\fP and \fBrr\fP.
 supported policy values are \fBother\fP, \fBfifo\fP and \fBrr\fP.
 .TP
 .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"
 .BR \-k ", " \-\-umask " \fImask\fP"
 This sets the umask of the process before starting it.
 This sets the umask of the process before starting it.
 .TP
 .TP

+ 97 - 1
utils/start-stop-daemon.c

@@ -111,6 +111,27 @@
 #include <error.h>
 #include <error.h>
 #endif
 #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 testmode = 0;
 static int quietmode = 0;
 static int quietmode = 0;
 static int exitnodo = 1;
 static int exitnodo = 1;
@@ -136,6 +157,11 @@ static const char *progname = "";
 static int nicelevel = 0;
 static int nicelevel = 0;
 static int umask_value = -1;
 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;
 static struct stat exec_stat;
 #if defined(OSHURD)
 #if defined(OSHURD)
 static struct proc_stat_list *procset = NULL;
 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 *proc_sched = NULL;
+static struct res_schedule *io_sched = NULL;
 
 
 static int schedule_length;
 static int schedule_length;
 static struct schedule_item *schedule = NULL;
 static struct schedule_item *schedule = NULL;
@@ -339,6 +366,8 @@ do_help(void)
 "  -P|--procsched <policy[:prio]>\n"
 "  -P|--procsched <policy[:prio]>\n"
 "                                use <policy> with <prio> for the kernel\n"
 "                                use <policy> with <prio> for the kernel\n"
 "                                  process scheduler (default prio is 0)\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"
 "  -k|--umask <mask>             change the umask to <mask> before starting\n"
 "  -b|--background               force the process to detach\n"
 "  -b|--background               force the process to detach\n"
 "  -m|--make-pidfile             create the pidfile before starting\n"
 "  -m|--make-pidfile             create the pidfile before starting\n"
@@ -492,6 +521,40 @@ parse_proc_schedule(const char *string)
 #endif
 #endif
 }
 }
 
 
+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
 static void
 set_proc_schedule(struct res_schedule *sched)
 set_proc_schedule(struct res_schedule *sched)
 {
 {
@@ -505,6 +568,26 @@ set_proc_schedule(struct res_schedule *sched)
 #endif
 #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
 static void
 parse_schedule_item(const char *string, struct schedule_item *item)
 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'},
 		{ "chuid",	  1, NULL, 'c'},
 		{ "nicelevel",	  1, NULL, 'N'},
 		{ "nicelevel",	  1, NULL, 'N'},
 		{ "procsched",	  1, NULL, 'P'},
 		{ "procsched",	  1, NULL, 'P'},
+		{ "iosched",	  1, NULL, 'I'},
 		{ "umask",	  1, NULL, 'k'},
 		{ "umask",	  1, NULL, 'k'},
 		{ "background",	  0, NULL, 'b'},
 		{ "background",	  0, NULL, 'b'},
 		{ "make-pidfile", 0, NULL, 'm'},
 		{ "make-pidfile", 0, NULL, 'm'},
@@ -618,11 +702,12 @@ parse_options(int argc, char * const *argv)
 	const char *signal_str = NULL;
 	const char *signal_str = NULL;
 	const char *schedule_str = NULL;
 	const char *schedule_str = NULL;
 	const char *proc_schedule_str = NULL;
 	const char *proc_schedule_str = NULL;
+	const char *io_schedule_str = NULL;
 	int c;
 	int c;
 
 
 	for (;;) {
 	for (;;) {
 		c = getopt_long(argc, argv,
 		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);
 		                longopts, NULL);
 		if (c == -1)
 		if (c == -1)
 			break;
 			break;
@@ -688,6 +773,9 @@ parse_options(int argc, char * const *argv)
 		case 'P':  /* --procsched */
 		case 'P':  /* --procsched */
 			proc_schedule_str = optarg;
 			proc_schedule_str = optarg;
 			break;
 			break;
+		case 'I':  /* --iosched */
+			io_schedule_str = optarg;
+			break;
 		case 'k':  /* --umask <mask> */
 		case 'k':  /* --umask <mask> */
 			umask_str = optarg;
 			umask_str = optarg;
 			break;
 			break;
@@ -721,6 +809,9 @@ parse_options(int argc, char * const *argv)
 	if (proc_schedule_str != NULL)
 	if (proc_schedule_str != NULL)
 		parse_proc_schedule(proc_schedule_str);
 		parse_proc_schedule(proc_schedule_str);
 
 
+	if (io_schedule_str != NULL)
+		parse_io_schedule(io_schedule_str);
+
 	if (umask_str != NULL) {
 	if (umask_str != NULL) {
 		if (parse_umask(umask_str, &umask_value) != 0)
 		if (parse_umask(umask_str, &umask_value) != 0)
 			badusage("umask value must be a positive number");
 			badusage("umask value must be a positive number");
@@ -1410,6 +1501,9 @@ main(int argc, char **argv)
 		if (proc_sched)
 		if (proc_sched)
 			printf(", with scheduling policy %s with priority %i",
 			printf(", with scheduling policy %s with priority %i",
 			       proc_sched->policy_name, proc_sched->priority);
 			       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");
 		printf(".\n");
 	}
 	}
 	if (testmode)
 	if (testmode)
@@ -1433,6 +1527,8 @@ main(int argc, char **argv)
 	}
 	}
 	if (proc_sched)
 	if (proc_sched)
 		set_proc_schedule(proc_sched);
 		set_proc_schedule(proc_sched);
+	if (io_sched)
+		set_io_schedule(io_sched);
 	if (umask_value >= 0)
 	if (umask_value >= 0)
 		umask(umask_value);
 		umask(umask_value);
 	if (mpidfile && pidfile != NULL) {
 	if (mpidfile && pidfile != NULL) {