policyscript: Add ability to specify a directory for multiple scripts
The policyscript directive allows for the specifcaion of a single script to define policy for all hardware on a system, which is good as a site/host specific utility, but it makes for difficult work in the event that vendors wish to provide guidance for only their own hardware (i.e. if vendor A wants certain hardware to follow affinity_hinting without affecting other hardware). To manage this, lets enhance policyscript to allow the specification of an entire directory, to which multiple scripts can be added. Semantics for this new directory feature are the same as for the single script case, except that the script exit codes have additional meaning: exit code 0 - the script indicates that the referenced irq relates to a device that this script recognizes and further script processing should stop exit code 1 - the script indicates that the referenced irq does not relate to a device the script recognizes, and script processing should continue exit code >2 - the script indicates an error has occured, and any output from it should be ignored, script processing should continue Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
This commit is contained in:
parent
d6abbe898b
commit
6e6ac7bc65
94
classify.c
94
classify.c
|
@ -3,6 +3,7 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
@ -493,37 +494,22 @@ static void parse_user_policy_key(char *buf, int irq, struct user_irq_policy *po
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls out to a possibly user defined script to get user assigned policy
|
||||
* aspects for a given irq. A value of -1 in a given field indicates no
|
||||
* policy was given and that system defaults should be used
|
||||
*/
|
||||
static void get_irq_user_policy(char *path, int irq, struct user_irq_policy *pol)
|
||||
static int run_script_for_policy(char *script, char *path, int irq, struct user_irq_policy *pol)
|
||||
{
|
||||
char *cmd;
|
||||
char *brc;
|
||||
FILE *output;
|
||||
char buffer[128];
|
||||
char *brc;
|
||||
|
||||
memset(pol, -1, sizeof(struct user_irq_policy));
|
||||
|
||||
/* Return defaults if no script was given */
|
||||
if (!polscript)
|
||||
return;
|
||||
|
||||
/* Use SYSFS_DIR for irq has no sysfs entries */
|
||||
if (!path)
|
||||
path = SYSFS_DIR;
|
||||
|
||||
cmd = alloca(strlen(path)+strlen(polscript)+64);
|
||||
cmd = alloca(strlen(path)+strlen(script)+64);
|
||||
if (!cmd)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
sprintf(cmd, "exec %s %s %d", polscript, path, irq);
|
||||
sprintf(cmd, "exec %s %s %d", script, path, irq);
|
||||
output = popen(cmd, "r");
|
||||
if (!output) {
|
||||
log(TO_ALL, LOG_WARNING, "Unable to execute user policy script %s\n", polscript);
|
||||
return;
|
||||
log(TO_ALL, LOG_WARNING, "Unable to execute user policy script %s\n", script);
|
||||
return 1; /* tell caller to ignore this script */
|
||||
}
|
||||
|
||||
while(!feof(output)) {
|
||||
|
@ -531,7 +517,69 @@ static void get_irq_user_policy(char *path, int irq, struct user_irq_policy *pol
|
|||
if (brc)
|
||||
parse_user_policy_key(brc, irq, pol);
|
||||
}
|
||||
pclose(output);
|
||||
return WEXITSTATUS(pclose(output));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls out to a possibly user defined script to get user assigned policy
|
||||
* aspects for a given irq. A value of -1 in a given field indicates no
|
||||
* policy was given and that system defaults should be used
|
||||
*/
|
||||
static void get_irq_user_policy(char *path, int irq, struct user_irq_policy *pol)
|
||||
{
|
||||
struct stat sbuf;
|
||||
DIR *poldir;
|
||||
struct dirent *entry;
|
||||
int ret;
|
||||
char script[1024];
|
||||
|
||||
memset(pol, -1, sizeof(struct user_irq_policy));
|
||||
|
||||
/* Return defaults if no script was given */
|
||||
if (!polscript)
|
||||
return;
|
||||
|
||||
if (stat(polscript, &sbuf))
|
||||
return;
|
||||
|
||||
/* Use SYSFS_DIR for irq has no sysfs entries */
|
||||
if (!path)
|
||||
path = SYSFS_DIR;
|
||||
|
||||
if (!S_ISDIR(sbuf.st_mode)) {
|
||||
if (run_script_for_policy(polscript, path, irq, pol) != 0) {
|
||||
log(TO_CONSOLE, LOG_ERR, "policy script returned non-zero code! skipping user policy\n");
|
||||
memset(pol, -1, sizeof(struct user_irq_policy));
|
||||
}
|
||||
} else {
|
||||
/* polscript is a directory, user multiple script semantics */
|
||||
poldir = opendir(polscript);
|
||||
|
||||
if (poldir) {
|
||||
while ((entry = readdir(poldir)) != NULL) {
|
||||
snprintf(script, sizeof(script), "%s/%s", polscript, entry->d_name);
|
||||
if (stat(script, &sbuf))
|
||||
continue;
|
||||
if (S_ISREG(sbuf.st_mode)) {
|
||||
memset(pol, -1, sizeof(struct user_irq_policy));
|
||||
ret = run_script_for_policy(script, path, irq, pol);
|
||||
if ((ret < 0) || (ret >= 2)) {
|
||||
log(TO_CONSOLE, LOG_ERR, "Error executing policy script %s : %d\n", script, ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* a ret of 1 means this script isn't
|
||||
* for this irq
|
||||
*/
|
||||
if (ret == 1)
|
||||
continue;
|
||||
|
||||
log(TO_CONSOLE, LOG_DEBUG, "Accepting script %s to define policy for irq %d\n", script, irq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_for_module_ban(char *name)
|
||||
|
|
21
irqbalance.1
21
irqbalance.1
|
@ -80,7 +80,7 @@ The default value for deepestcache is 2.
|
|||
|
||||
.TP
|
||||
.B -l, --policyscript=<script>
|
||||
When specified, the referenced script will execute once for each discovered IRQ,
|
||||
When specified, the referenced script or directory will execute once for each discovered IRQ,
|
||||
with the sysfs device path and IRQ number passed as arguments. Note that the
|
||||
device path argument will point to the parent directory from which the IRQ
|
||||
attributes directory may be directly opened.
|
||||
|
@ -90,7 +90,6 @@ and will be captured and interpreted by irqbalance. Irqbalance expects a zero
|
|||
exit code from the provided utility. Recognized key=value pairs are:
|
||||
.TP
|
||||
.I ban=[true | false]
|
||||
.TP
|
||||
Directs irqbalance to exclude the passed in IRQ from balancing.
|
||||
.TP
|
||||
.I balance_level=[none | package | cache | core]
|
||||
|
@ -106,6 +105,24 @@ This option allows for that hardware provided information to be overridden, so
|
|||
that irqbalance can bias IRQ affinity for these devices toward its most local
|
||||
node. Note that specifying a -1 here forces irqbalance to consider an interrupt
|
||||
from a device to be equidistant from all nodes.
|
||||
.TP
|
||||
Note that, if a directory is specified rather than a regular file, all files in
|
||||
the directory will be considered policy scripts, and executed on adding of an
|
||||
irq to a database. If such a directory is specified, scripts in the directory
|
||||
must additionally exit with one of the following exit codes:
|
||||
.TP
|
||||
.I 0
|
||||
This indicates the script has a policy for the referenced irq, and that further
|
||||
script processing should stop
|
||||
.TP
|
||||
.I 1
|
||||
This indicates that the script has no policy for the referenced irq, and that
|
||||
script processing should continue
|
||||
.TP
|
||||
.I 2
|
||||
This indicates that an error has occured in the script, and it should be skipped
|
||||
(further processing to continue)
|
||||
|
||||
.TP
|
||||
.B -s, --pid=<file>
|
||||
Have irqbalance write its process id to the specified file. By default no
|
||||
|
|
Loading…
Reference in a new issue