void-packages/srcpkgs/irqbalance/patches/irqbalance-2011-08-09.patch

1585 lines
40 KiB
Diff

diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644
index f5e9428..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,3 +0,0 @@
-This is all tracked in the SVN repo. This file is just here to keep the
-autotools from complaining
-
diff --git a/Makefile.am b/Makefile.am
index 9847232..188e34f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -22,17 +22,17 @@
AUTOMAKE_OPTIONS = no-dependencies
ACLOCAL_AMFLAGS = -I m4
-EXTRA_DIST = README INSTALL COPYING autogen.sh m4/cap-ng.m4 misc/irqbalance.service
-
+EXTRA_DIST = INSTALL COPYING autogen.sh misc/irqbalance.service
+
INCLUDES = -I${top_srcdir}
-LIBS = $(CAPNG_LDADD) $(GLIB_LIBS) @LIBS@
-AM_CFLAGS = $(GLIB_CFLAGS)
+AM_CFLAGS = $(LIBCAP_NG_CFLAGS) $(GLIB_CFLAGS)
AM_CPPFLAGS = -W -Wall -Wshadow -Wformat -Wundef -D_GNU_SOURCE
noinst_HEADERS = bitmap.h constants.h cpumask.h irqbalance.h non-atomic.h \
types.h
sbin_PROGRAMS = irqbalance
irqbalance_SOURCES = activate.c bitmap.c classify.c cputree.c irqbalance.c \
- irqlist.c numa.c placement.c powermode.c procinterrupts.c
+ irqlist.c numa.c placement.c procinterrupts.c
+irqbalance_LDADD = $(LIBCAP_NG_LIBS) $(GLIB_LIBS)
dist_man_MANS = irqbalance.1
CONFIG_CLEAN_FILES = debug*.list config/*
@@ -40,3 +40,6 @@ clean-generic:
rm -rf autom4te*.cache
rm -f *.rej *.orig *~
+if LOCAL_GLIB
+SUBDIRS = glib-local
+endif
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 7cc0277..0000000
--- a/NEWS
+++ /dev/null
@@ -1 +0,0 @@
-No news currently
diff --git a/README b/README
deleted file mode 100644
index e69de29..0000000
diff --git a/activate.c b/activate.c
index 292c44a..02fc8dc 100644
--- a/activate.c
+++ b/activate.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -31,34 +32,63 @@
#include "irqbalance.h"
+static int check_affinity(struct irq_info *info, cpumask_t applied_mask)
+{
+ cpumask_t current_mask;
+ char buf[PATH_MAX];
+ char *line = NULL;
+ size_t size = 0;
+ FILE *file;
+
+ sprintf(buf, "/proc/irq/%i/smp_affinity", info->irq);
+ file = fopen(buf, "r");
+ if (!file)
+ return 1;
+ if (getline(&line, &size, file)==0) {
+ free(line);
+ fclose(file);
+ return 1;
+ }
+ cpumask_parse_user(line, strlen(line), current_mask);
+ fclose(file);
+ free(line);
+
+ return cpus_equal(applied_mask, current_mask);
+}
static void activate_mapping(struct irq_info *info, void *data __attribute__((unused)))
{
char buf[PATH_MAX];
FILE *file;
cpumask_t applied_mask;
+ int valid_mask = 0;
+
+ if ((hint_policy == HINT_POLICY_EXACT) &&
+ (!cpus_empty(info->affinity_hint))) {
+ applied_mask = info->affinity_hint;
+ valid_mask = 1;
+ } else if (info->assigned_obj) {
+ applied_mask = info->assigned_obj->mask;
+ valid_mask = 1;
+ if ((hint_policy == HINT_POLICY_SUBSET) &&
+ (!cpus_empty(info->affinity_hint)))
+ cpus_and(applied_mask, applied_mask, info->affinity_hint);
+ }
/*
* only activate mappings for irqs that have moved
*/
- if (!info->moved)
+ if (!info->moved && (!valid_mask || check_affinity(info, applied_mask)))
return;
if (!info->assigned_obj)
return;
-
sprintf(buf, "/proc/irq/%i/smp_affinity", info->irq);
file = fopen(buf, "w");
if (!file)
return;
- if ((hint_policy == HINT_POLICY_EXACT) &&
- (!cpus_empty(info->affinity_hint)))
- applied_mask = info->affinity_hint;
- else
- applied_mask = info->assigned_obj->mask;
-
cpumask_scnprintf(buf, PATH_MAX, applied_mask);
fprintf(file, "%s", buf);
fclose(file);
diff --git a/autogen.sh b/autogen.sh
index 5ad9f14..b792e8b 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,4 +1,5 @@
#! /bin/sh
set -x -e
+mkdir -p m4
# --no-recursive is available only in recent autoconf versions
autoreconf -fv --install
diff --git a/classify.c b/classify.c
index 124dab0..05b3bfb 100644
--- a/classify.c
+++ b/classify.c
@@ -52,6 +52,8 @@ static short class_codes[MAX_CLASS] = {
};
static GList *interrupts_db;
+static GList *new_irq_list;
+static GList *banned_irqs;
#define SYSDEV_DIR "/sys/bus/pci/devices"
@@ -63,6 +65,30 @@ static gint compare_ints(gconstpointer a, gconstpointer b)
return ai->irq - bi->irq;
}
+void add_banned_irq(int irq)
+{
+ struct irq_info find, *new;
+ GList *entry;
+
+ find.irq = irq;
+ entry = g_list_find_custom(banned_irqs, &find, compare_ints);
+ if (entry)
+ return;
+
+ new = calloc(sizeof(struct irq_info), 1);
+ if (!new) {
+ if (debug_mode)
+ printf("No memory to ban irq %d\n", irq);
+ return;
+ }
+
+ new->irq = irq;
+
+ banned_irqs = g_list_append(banned_irqs, new);
+ return;
+}
+
+
/*
* Inserts an irq_info struct into the intterupts_db list
* devpath points to the device directory in sysfs for the
@@ -90,6 +116,13 @@ static struct irq_info *add_one_irq_to_db(const char *devpath, int irq)
return NULL;
}
+ entry = g_list_find_custom(banned_irqs, &find, compare_ints);
+ if (entry) {
+ if (debug_mode)
+ printf("SKIPPING BANNED IRQ %d\n", irq);
+ return NULL;
+ }
+
new = calloc(sizeof(struct irq_info), 1);
if (!new)
return NULL;
@@ -175,6 +208,43 @@ out:
return new;
}
+static int check_for_irq_ban(char *path, int irq)
+{
+ char *cmd;
+ int rc;
+
+ if (!banscript)
+ return 0;
+
+ cmd = alloca(strlen(path)+strlen(banscript)+32);
+ if (!cmd)
+ return 0;
+
+ sprintf(cmd, "%s %s %d",banscript, path, irq);
+ rc = system(cmd);
+
+ /*
+ * The system command itself failed
+ */
+ if (rc == -1) {
+ if (debug_mode)
+ printf("%s failed, please check the --banscript option\n", cmd);
+ else
+ syslog(LOG_INFO, "%s failed, please check the --banscript option\n", cmd);
+ return 0;
+ }
+
+ if (WEXITSTATUS(rc)) {
+ if (debug_mode)
+ printf("irq %d is baned by %s\n", irq, banscript);
+ else
+ syslog(LOG_INFO, "irq %d is baned by %s\n", irq, banscript);
+ return 1;
+ }
+ return 0;
+
+}
+
/*
* Figures out which interrupt(s) relate to the device we're looking at in dirname
*/
@@ -199,6 +269,10 @@ static void build_one_dev_entry(const char *dirname)
irqnum = strtol(entry->d_name, NULL, 10);
if (irqnum) {
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
+ if (check_for_irq_ban(path, irqnum)) {
+ add_banned_irq(irqnum);
+ continue;
+ }
new = add_one_irq_to_db(path, irqnum);
if (!new)
continue;
@@ -221,6 +295,11 @@ static void build_one_dev_entry(const char *dirname)
*/
if (irqnum) {
sprintf(path, "%s/%s", SYSDEV_DIR, dirname);
+ if (check_for_irq_ban(path, irqnum)) {
+ add_banned_irq(irqnum);
+ goto done;
+ }
+
new = add_one_irq_to_db(path, irqnum);
if (!new)
goto done;
@@ -248,6 +327,8 @@ void rebuild_irq_db(void)
{
DIR *devdir = opendir(SYSDEV_DIR);
struct dirent *entry;
+ GList *gentry;
+ struct irq_info *ninfo, *iinfo;
free_irq_db();
@@ -263,22 +344,46 @@ void rebuild_irq_db(void)
build_one_dev_entry(entry->d_name);
} while (entry != NULL);
+
closedir(devdir);
+
+ if (!new_irq_list)
+ return;
+ gentry = g_list_first(new_irq_list);
+ while(gentry) {
+ ninfo = gentry->data;
+ iinfo = get_irq_info(ninfo->irq);
+ new_irq_list = g_list_remove(gentry, ninfo);
+ if (!iinfo) {
+ if (debug_mode)
+ printf("Adding untracked IRQ %d to database\n", ninfo->irq);
+ interrupts_db = g_list_append(interrupts_db, ninfo);
+ } else
+ free(ninfo);
+
+ gentry = g_list_first(new_irq_list);
+ }
+ g_list_free(new_irq_list);
+ new_irq_list = NULL;
+
}
-struct irq_info *add_misc_irq(int irq)
+struct irq_info *add_new_irq(int irq)
{
- struct irq_info *new;
+ struct irq_info *new, *nnew;
new = calloc(sizeof(struct irq_info), 1);
- if (!new)
+ nnew = calloc(sizeof(struct irq_info), 1);
+ if (!new || !nnew)
return NULL;
new->irq = irq;
new->type = IRQ_TYPE_LEGACY;
new->class = IRQ_OTHER;
new->numa_node = get_numa_node(-1);
+ memcpy(nnew, new, sizeof(struct irq_info));
interrupts_db = g_list_append(interrupts_db, new);
+ new_irq_list = g_list_append(new_irq_list, nnew);
return new;
}
@@ -307,7 +412,7 @@ struct irq_info *get_irq_info(int irq)
void migrate_irq(GList **from, GList **to, struct irq_info *info)
{
GList *entry;
- struct irq_info find, *tmp;;
+ struct irq_info find, *tmp;
find.irq = info->irq;
entry = g_list_find_custom(*from, &find, compare_ints);
@@ -325,18 +430,9 @@ static gint sort_irqs(gconstpointer A, gconstpointer B)
a = (struct irq_info*)A;
b = (struct irq_info*)B;
- if (a->class < b->class)
- return 1;
- if (a->class > b->class)
- return -1;
- if (a->load < b->load)
- return 1;
- if (a->load > b->load)
- return -1;
- if (a<b)
+ if (a->class < b->class || a->load < b->load || a < b)
return 1;
return -1;
-
}
void sort_irq_list(GList **list)
diff --git a/configure.ac b/configure.ac
index eed55ba..1230d66 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,49 +1,12 @@
-dnl
-define([AC_INIT_NOTICE],
-[### Generated automatically using autoconf version] AC_ACVERSION [
-### Copyright 2009 Steve Grubb <sgrubb@redhat.com>
-###
-### Permission is hereby granted, free of charge, to any person obtaining a
-### copy of this software and associated documentation files (the "Software"),
-### to deal in the Software without restriction, including without limitation
-### the rights to use, copy, modify, merge, publish, distribute, sublicense,
-### and/or sell copies of the Software, and to permit persons to whom the
-### Software is furnished to do so, subject to the following conditions:
-###
-### The above copyright notice and this permission notice shall be included
-### in all copies or substantial portions of the Software.
-###
-### THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-### IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-### FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-### THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-### OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-### ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-### OTHER DEALINGS IN THE SOFTWARE.
-###
-### For usage, run `./configure --help'
-### For more detailed information on installation, read the file `INSTALL'.
-###
-### If configuration succeeds, status is in the file `config.status'.
-### A log of configuration tests is in `config.log'.
-])
-
-AC_REVISION($Revision: 1.3 $)dnl
AC_INIT(irqbalance,1.0.3)
AC_PREREQ(2.12)dnl
AM_CONFIG_HEADER(config.h)
-echo Configuring irqbalance $VERSION
-
AC_CONFIG_MACRO_DIR([m4])
-AC_CANONICAL_TARGET
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([foreign])
AM_PROG_LIBTOOL
AC_SUBST(LIBTOOL_DEPS)
-AC_MSG_NOTICE()
-AC_MSG_NOTICE([Checking for programs])
-
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_AWK
@@ -55,9 +18,6 @@ AS_IF([test "$enable_numa" = "no"],[
ac_cv_lib_numa_numa_available=no
])
-AC_MSG_NOTICE
-AC_MSG_NOTICE([echo Checking for header files])
-
AC_HEADER_STDC
AC_CHECK_HEADERS([numa.h])
@@ -70,10 +30,57 @@ AC_C_CONST
AC_C_INLINE
AM_PROG_CC_C_O
-PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28])
-LIBCAP_NG_PATH
+AC_ARG_WITH([glib2],
+ [AS_HELP_STRING([--without-glib2],
+ [Don't use system glib2 library. Use local implementation instead.])],
+ [],
+ [with_glib2=check])
+
+local_glib2=
+AS_IF(
+ [test "x$with_glib2" = xyes],
+ [PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28])],
+
+ [test "x$with_glib2" = xno],
+ [local_glib2="yes"],
+
+ [PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28], [], [local_glib2="yes"])]
+)
+
+AS_IF(
+ [test "x$local_glib2" = xyes],
+ [
+ GLIB_CFLAGS=-I./glib-local
+ GLIB_LIBS=glib-local/libglib.a
+ AC_SUBST(GLIB_CFLAGS)
+ AC_SUBST(GLIB_LIBS)
+ AC_MSG_WARN(Using locale implementation of GList functions)
+ ]
+)
+
+AM_CONDITIONAL([LOCAL_GLIB], [test "x$local_glib2" = "xyes"])
+
+AC_ARG_WITH([libcap-ng],
+ AS_HELP_STRING([libcap-ng], [Add libcap-ng-support @<:@default=auto@:>@]))
+
+AS_IF(
+ [test "x$libcap_ng" != "xno"],
+ [
+ PKG_CHECK_MODULES([LIBCAP_NG], [libcap-ng],
+ [AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support])],
+ [
+ AS_IF(
+ [test "x$libcap_ng" = "xyes"],
+ [
+ AC_MSG_ERROR([libcap-ng not found])
+ ]
+ )
+ ]
+ )
+ ]
+)
-AC_OUTPUT(Makefile)
+AC_OUTPUT(Makefile glib-local/Makefile)
AC_MSG_NOTICE()
AC_MSG_NOTICE([irqbalance Version: $VERSION])
diff --git a/cputree.c b/cputree.c
index af4fd3a..9568967 100644
--- a/cputree.c
+++ b/cputree.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
diff --git a/glib-local/Makefile.am b/glib-local/Makefile.am
new file mode 100644
index 0000000..336b56e
--- /dev/null
+++ b/glib-local/Makefile.am
@@ -0,0 +1,8 @@
+## Process this file with automake to produce Makefile.in
+noinst_LIBRARIES = libglib.a
+
+libglib_a_SOURCES = glist.c
+
+libglib_a_CFLAGS = @GLIB_CFLAGS@
+
+noinst_HEADERS = glib.h glist.h
diff --git a/glib-local/glib.h b/glib-local/glib.h
new file mode 100644
index 0000000..5874892
--- /dev/null
+++ b/glib-local/glib.h
@@ -0,0 +1 @@
+#include <glist.h>
diff --git a/glib-local/glist.c b/glib-local/glist.c
new file mode 100644
index 0000000..6fa1761
--- /dev/null
+++ b/glib-local/glist.c
@@ -0,0 +1,381 @@
+#include <stdlib.h>
+
+#include "glist.h"
+
+/**
+ * g_list_free:
+ * @list: a #GList
+ *
+ * Frees all of the memory used by a #GList.
+ * The freed elements are returned to the slice allocator.
+ *
+ * <note><para>
+ * If list elements contain dynamically-allocated memory,
+ * you should either use g_list_free_full() or free them manually
+ * first.
+ * </para></note>
+ */
+void
+g_list_free (GList *list)
+{
+ GList *l = list;
+
+ while(l) {
+ GList *tmp = l->next;
+ free(l);
+ l = tmp;
+ }
+}
+
+/**
+ * g_list_last:
+ * @list: a #GList
+ *
+ * Gets the last element in a #GList.
+ *
+ * Returns: the last element in the #GList,
+ * or %NULL if the #GList has no elements
+ */
+GList*
+g_list_last (GList *list)
+{
+ if (list)
+ {
+ while (list->next)
+ list = list->next;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_append:
+ * @list: a pointer to a #GList
+ * @data: the data for the new element
+ *
+ * Adds a new element on to the end of the list.
+ *
+ * <note><para>
+ * The return value is the new start of the list, which
+ * may have changed, so make sure you store the new value.
+ * </para></note>
+ *
+ * <note><para>
+ * Note that g_list_append() has to traverse the entire list
+ * to find the end, which is inefficient when adding multiple
+ * elements. A common idiom to avoid the inefficiency is to prepend
+ * the elements and reverse the list when all elements have been added.
+ * </para></note>
+ *
+ * |[
+ * /&ast; Notice that these are initialized to the empty list. &ast;/
+ * GList *list = NULL, *number_list = NULL;
+ *
+ * /&ast; This is a list of strings. &ast;/
+ * list = g_list_append (list, "first");
+ * list = g_list_append (list, "second");
+ *
+ * /&ast; This is a list of integers. &ast;/
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (27));
+ * number_list = g_list_append (number_list, GINT_TO_POINTER (14));
+ * ]|
+ *
+ * Returns: the new start of the #GList
+ */
+GList*
+g_list_append (GList *list,
+ gpointer data)
+{
+ GList *new_list;
+ GList *last;
+
+ new_list = malloc(sizeof(*new_list));
+ new_list->data = data;
+ new_list->next = NULL;
+
+ if (list)
+ {
+ last = g_list_last (list);
+ /* g_assert (last != NULL); */
+ last->next = new_list;
+ new_list->prev = last;
+
+ return list;
+ }
+ else
+ {
+ new_list->prev = NULL;
+ return new_list;
+ }
+}
+
+static inline GList*
+_g_list_remove_link (GList *list,
+ GList *link)
+{
+ if (link)
+ {
+ if (link->prev)
+ link->prev->next = link->next;
+ if (link->next)
+ link->next->prev = link->prev;
+
+ if (link == list)
+ list = list->next;
+
+ link->next = NULL;
+ link->prev = NULL;
+ }
+
+ return list;
+}
+
+/**
+ * g_list_delete_link:
+ * @list: a #GList
+ * @link_: node to delete from @list
+ *
+ * Removes the node link_ from the list and frees it.
+ * Compare this to g_list_remove_link() which removes the node
+ * without freeing it.
+ *
+ * Returns: the new head of @list
+ */
+GList*
+g_list_delete_link (GList *list,
+ GList *link_)
+{
+ list = _g_list_remove_link (list, link_);
+ free (link_);
+
+ return list;
+}
+
+/**
+ * g_list_first:
+ * @list: a #GList
+ *
+ * Gets the first element in a #GList.
+ *
+ * Returns: the first element in the #GList,
+ * or %NULL if the #GList has no elements
+ */
+GList*
+g_list_first (GList *list)
+{
+ if (list)
+ {
+ while (list->prev)
+ list = list->prev;
+ }
+
+ return list;
+}
+
+static GList *
+g_list_sort_merge (GList *l1,
+ GList *l2,
+ GFunc compare_func,
+ gpointer user_data)
+{
+ GList list, *l, *lprev;
+ gint cmp;
+
+ l = &list;
+ lprev = NULL;
+
+ while (l1 && l2)
+ {
+ cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
+
+ if (cmp <= 0)
+ {
+ l->next = l1;
+ l1 = l1->next;
+ }
+ else
+ {
+ l->next = l2;
+ l2 = l2->next;
+ }
+ l = l->next;
+ l->prev = lprev;
+ lprev = l;
+ }
+ l->next = l1 ? l1 : l2;
+ l->next->prev = l;
+
+ return list.next;
+}
+
+static GList*
+g_list_sort_real (GList *list,
+ GFunc compare_func,
+ gpointer user_data)
+{
+ GList *l1, *l2;
+
+ if (!list)
+ return NULL;
+ if (!list->next)
+ return list;
+
+ l1 = list;
+ l2 = list->next;
+
+ while ((l2 = l2->next) != NULL)
+ {
+ if ((l2 = l2->next) == NULL)
+ break;
+ l1 = l1->next;
+ }
+ l2 = l1->next;
+ l1->next = NULL;
+
+ return g_list_sort_merge (g_list_sort_real (list, compare_func, user_data),
+ g_list_sort_real (l2, compare_func, user_data),
+ compare_func,
+ user_data);
+}
+
+/**
+ * g_list_sort:
+ * @list: a #GList
+ * @compare_func: the comparison function used to sort the #GList.
+ * This function is passed the data from 2 elements of the #GList
+ * and should return 0 if they are equal, a negative value if the
+ * first element comes before the second, or a positive value if
+ * the first element comes after the second.
+ *
+ * Sorts a #GList using the given comparison function.
+ *
+ * Returns: the start of the sorted #GList
+ */
+/**
+ * GCompareFunc:
+ * @a: a value.
+ * @b: a value to compare with.
+ * @Returns: negative value if @a &lt; @b; zero if @a = @b; positive
+ * value if @a > @b.
+ *
+ * Specifies the type of a comparison function used to compare two
+ * values. The function should return a negative integer if the first
+ * value comes before the second, 0 if they are equal, or a positive
+ * integer if the first value comes after the second.
+ **/
+GList *
+g_list_sort (GList *list,
+ GCompareFunc compare_func)
+{
+ return g_list_sort_real (list, (GFunc) compare_func, NULL);
+
+}
+
+/**
+ * g_list_length:
+ * @list: a #GList
+ *
+ * Gets the number of elements in a #GList.
+ *
+ * <note><para>
+ * This function iterates over the whole list to
+ * count its elements.
+ * </para></note>
+ *
+ * Returns: the number of elements in the #GList
+ */
+guint
+g_list_length (GList *list)
+{
+ guint length;
+
+ length = 0;
+ while (list)
+ {
+ length++;
+ list = list->next;
+ }
+
+ return length;
+}
+
+/**
+ * g_list_foreach:
+ * @list: a #GList
+ * @func: the function to call with each element's data
+ * @user_data: user data to pass to the function
+ *
+ * Calls a function for each element of a #GList.
+ */
+/**
+ * GFunc:
+ * @data: the element's data.
+ * @user_data: user data passed to g_list_foreach() or
+ * g_slist_foreach().
+ *
+ * Specifies the type of functions passed to g_list_foreach() and
+ * g_slist_foreach().
+ **/
+void
+g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data)
+{
+ while (list)
+ {
+ GList *next = list->next;
+ (*func) (list->data, user_data);
+ list = next;
+ }
+}
+
+/**
+ * g_list_free_full:
+ * @list: a pointer to a #GList
+ * @free_func: the function to be called to free each element's data
+ *
+ * Convenience method, which frees all the memory used by a #GList, and
+ * calls the specified destroy function on every element's data.
+ *
+ * Since: 2.28
+ */
+void
+g_list_free_full (GList *list,
+ GDestroyNotify free_func)
+{
+ g_list_foreach (list, (GFunc) free_func, NULL);
+ g_list_free (list);
+}
+
+/**
+ * g_list_find_custom:
+ * @list: a #GList
+ * @data: user data passed to the function
+ * @func: the function to call for each element.
+ * It should return 0 when the desired element is found
+ *
+ * Finds an element in a #GList, using a supplied function to
+ * find the desired element. It iterates over the list, calling
+ * the given function which should return 0 when the desired
+ * element is found. The function takes two #gconstpointer arguments,
+ * the #GList element's data as the first argument and the
+ * given user data.
+ *
+ * Returns: the found #GList element, or %NULL if it is not found
+ */
+GList*
+g_list_find_custom (GList *list,
+ gconstpointer data,
+ GCompareFunc func)
+{
+ g_return_val_if_fail (func != NULL, list);
+
+ while (list)
+ {
+ if (! func (list->data, data))
+ return list;
+ list = list->next;
+ }
+
+ return NULL;
+}
diff --git a/glib-local/glist.h b/glib-local/glist.h
new file mode 100644
index 0000000..47f2cfe
--- /dev/null
+++ b/glib-local/glist.h
@@ -0,0 +1,56 @@
+#ifndef __G_LIST_H__
+#define __G_LIST_H__
+
+typedef int gint;
+typedef unsigned int guint;
+typedef void* gpointer;
+typedef const void *gconstpointer;
+typedef gint (*GCompareFunc) (gconstpointer a,
+ gconstpointer b);
+typedef gint (*GCompareDataFunc) (gconstpointer a,
+ gconstpointer b,
+ gpointer user_data);
+typedef void (*GFunc) (gpointer data,
+ gpointer user_data);
+typedef void (*GDestroyNotify) (gpointer data);
+
+struct _GList;
+typedef struct _GList GList;
+
+struct _GList
+{
+ gpointer data;
+ GList *next;
+ GList *prev;
+};
+
+/* Doubly linked lists
+ */
+void g_list_free (GList *list);
+GList* g_list_append (GList *list,
+ gpointer data);
+GList* g_list_delete_link (GList *list,
+ GList *link_);
+GList* g_list_first (GList *list);
+GList* g_list_sort (GList *list,
+ GCompareFunc compare_func);
+guint g_list_length (GList *list);
+void g_list_foreach (GList *list,
+ GFunc func,
+ gpointer user_data);
+void g_list_free_full (GList *list,
+ GDestroyNotify free_func);
+GList* g_list_find_custom (GList *list,
+ gconstpointer data,
+ GCompareFunc func);
+
+#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
+#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
+
+#define g_return_val_if_fail(expr,val) do { \
+ if (expr) { } else \
+ { \
+ return (val); \
+ } } while(0);
+
+#endif /* __G_LIST_H__ */
diff --git a/irqbalance.1 b/irqbalance.1
index 55fc15f..20105bc 100644
--- a/irqbalance.1
+++ b/irqbalance.1
@@ -39,7 +39,11 @@ Causes irqbalance to be run once, after which the daemon exits
.TP
.B --debug
-Causes irqbalance to run in the foreground and extra debug information to be printed
+Causes irqbalance to print extra debug information. Implies --foreground
+
+.TP
+.B --foreground
+Causes irqbalance to run in the foreground (without --debug)
.TP
.B --hintpolicy=[exact | subset | ignore]
@@ -62,6 +66,30 @@ average cpu softirq workload, and no cpus are more than 1 standard deviation
above (and have more than 1 irq assigned to them), attempt to place 1 cpu in
powersave mode. In powersave mode, a cpu will not have any irqs balanced to it,
in an effort to prevent that cpu from waking up without need.
+
+.TP
+.B --banirq=<irqnum>
+Add the specified irq list to the set of banned irqs. irqbalance will not affect
+the affinity of any irqs on the banned list, allowing them to be specified
+manually. This option is addative and can be specified multiple times
+
+.TP
+.B --banscript=<script>
+Execute the specified script for each irq that is discovered, passing the sysfs
+path to the associated device as the first argument, and the irq vector as the
+second. An exit value of 0 tells irqbalance that this interrupt should balanced
+and managed as a normal irq, while a non-zero exit code indicates this irq
+should be ignored by irqbalance completely (see --banirq above). Use of this
+script provides users the ability to dynamically select which irqs get exluded
+from balancing, and provides an opportunity for manual affinity setting in one
+single code point.
+
+.TP
+.B --pid=<file>
+Have irqbalance write its process id to the specified file. By default no
+pidfile is written. The written pidfile is automatically unlinked when
+irqbalance exits.
+
.SH "ENVIRONMENT VARIABLES"
.TP
.B IRQBALANCE_ONESHOT
@@ -75,9 +103,10 @@ Same as --debug
.B IRQBALANCE_BANNED_CPUS
Provides a mask of cpus which irqbalance should ignore and never assign interrupts to
+.SH "SIGNALS"
.TP
-.B IRQBALANCE_BANNED_INTERRUPTS
-A list of space delimited IRQ numbers that irqbalance should not touch
+.B SIGHUP
+Forces a rescan of the available irqs and system topology
.SH "Homepage"
http://code.google.com/p/irqbalance
diff --git a/irqbalance.c b/irqbalance.c
index 99c5db7..fbe6ac6 100644
--- a/irqbalance.c
+++ b/irqbalance.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -27,6 +28,10 @@
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#endif
@@ -39,12 +44,15 @@
volatile int keep_going = 1;
int one_shot_mode;
int debug_mode;
+int foreground_mode;
int numa_avail;
-int need_cpu_rescan;
+int need_rescan;
extern cpumask_t banned_cpus;
enum hp_e hint_policy = HINT_POLICY_SUBSET;
unsigned long power_thresh = ULONG_MAX;
unsigned long long cycle_count = 0;
+char *pidfile = NULL;
+char *banscript = NULL;
void sleep_approx(int seconds)
{
@@ -64,32 +72,45 @@ void sleep_approx(int seconds)
struct option lopts[] = {
{"oneshot", 0, NULL, 'o'},
{"debug", 0, NULL, 'd'},
+ {"foreground", 0, NULL, 'f'},
{"hintpolicy", 1, NULL, 'h'},
{"powerthresh", 1, NULL, 'p'},
+ {"banirq", 1 , NULL, 'i'},
+ {"banscript", 1, NULL, 'b'},
+ {"pid", 1, NULL, 's'},
{0, 0, 0, 0}
};
static void usage(void)
{
- printf("irqbalance [--oneshot | -o] [--debug | -d] [--hintpolicy= | -h [exact|subset|ignore]]\n");
- printf(" [--powerthresh= | -p <off> | <n>]\n");
+ printf("irqbalance [--oneshot | -o] [--debug | -d] [--foreground | -f] [--hintpolicy= | -h [exact|subset|ignore]]\n");
+ printf(" [--powerthresh= | -p <off> | <n>] [--banirq= | -i <n>]\n");
}
static void parse_command_line(int argc, char **argv)
{
int opt;
int longind;
+ unsigned long val;
while ((opt = getopt_long(argc, argv,
- "odh:p:",
+ "odfh:i:p:s:",
lopts, &longind)) != -1) {
switch(opt) {
case '?':
usage();
exit(1);
+ break;
+ case 'b':
+ banscript = strdup(optarg);
+ break;
case 'd':
debug_mode=1;
+ foreground_mode=1;
+ break;
+ case 'f':
+ foreground_mode=1;
break;
case 'h':
if (!strncmp(optarg, "exact", strlen(optarg)))
@@ -103,6 +124,14 @@ static void parse_command_line(int argc, char **argv)
exit(1);
}
break;
+ case 'i':
+ val = strtoull(optarg, NULL, 10);
+ if (val == ULONG_MAX) {
+ usage();
+ exit(1);
+ }
+ add_banned_irq((int)val);
+ break;
case 'p':
if (!strncmp(optarg, "off", strlen(optarg)))
power_thresh = ULONG_MAX;
@@ -117,6 +146,9 @@ static void parse_command_line(int argc, char **argv)
case 'o':
one_shot_mode=1;
break;
+ case 's':
+ pidfile = optarg;
+ break;
}
}
}
@@ -172,18 +204,34 @@ static void handler(int signum)
keep_going = 0;
}
+static void force_rescan(int signum)
+{
+ if (cycle_count)
+ need_rescan = 1;
+}
+
int main(int argc, char** argv)
{
- struct sigaction action;
+ struct sigaction action, hupaction;
#ifdef HAVE_GETOPT_LONG
parse_command_line(argc, argv);
#else
- if (argc>1 && strstr(argv[1],"--debug"))
+ if (argc>1 && strstr(argv[1],"--debug")) {
debug_mode=1;
+ foreground_mode=1;
+ }
+ if (argc>1 && strstr(argv[1],"--foreground"))
+ foreground_mode=1;
if (argc>1 && strstr(argv[1],"--oneshot"))
one_shot_mode=1;
#endif
+
+ /*
+ * Open the syslog connection
+ */
+ openlog(argv[0], 0, LOG_DAEMON);
+
if (getenv("IRQBALANCE_BANNED_CPUS")) {
cpumask_parse_user(getenv("IRQBALANCE_BANNED_CPUS"), strlen(getenv("IRQBALANCE_BANNED_CPUS")), banned_cpus);
}
@@ -212,17 +260,35 @@ int main(int argc, char** argv)
/* On single core UP systems irqbalance obviously has no work to do */
- if (core_count<2)
+ if (core_count<2) {
+ char *msg = "Balaincing is ineffective on systems with a "
+ "single cache domain. Shutting down\n";
+
+ if (debug_mode)
+ printf("%s", msg);
+ else
+ syslog(LOG_INFO, "%s", msg);
exit(EXIT_SUCCESS);
+ }
/* On dual core/hyperthreading shared cache systems just do a one shot setup */
if (cache_domain_count==1)
one_shot_mode = 1;
- if (!debug_mode)
+ if (!foreground_mode) {
+ int pidfd = -1;
if (daemon(0,0))
exit(EXIT_FAILURE);
+ /* Write pidfile */
+ if (pidfile && (pidfd = open(pidfile,
+ O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) {
+ char str[16];
+ snprintf(str, sizeof(str), "%u\n", getpid());
+ write(pidfd, str, strlen(str));
+ close(pidfd);
+ }
+ }
- openlog(argv[0], 0, LOG_DAEMON);
#ifdef HAVE_LIBCAP_NG
// Drop capabilities
@@ -236,6 +302,11 @@ int main(int argc, char** argv)
parse_proc_interrupts();
parse_proc_stat();
+ hupaction.sa_handler = force_rescan;
+ sigemptyset(&hupaction.sa_mask);
+ hupaction.sa_flags = 0;
+ sigaction(SIGHUP, &hupaction, NULL);
+
while (keep_going) {
sleep_approx(SLEEP_INTERVAL);
if (debug_mode)
@@ -247,8 +318,8 @@ int main(int argc, char** argv)
parse_proc_stat();
/* cope with cpu hotplug -- detected during /proc/interrupts parsing */
- if (need_cpu_rescan) {
- need_cpu_rescan = 0;
+ if (need_rescan) {
+ need_rescan = 0;
/* if there's a hotplug event we better turn off power mode for a bit until things settle */
power_mode = 0;
if (debug_mode)
@@ -282,5 +353,10 @@ int main(int argc, char** argv)
}
free_object_tree();
+
+ /* Remove pidfile */
+ if (!foreground_mode && pidfile)
+ unlink(pidfile);
+
return EXIT_SUCCESS;
}
diff --git a/irqbalance.h b/irqbalance.h
index 4e85325..e46f31f 100644
--- a/irqbalance.h
+++ b/irqbalance.h
@@ -9,6 +9,7 @@
#include <stdint.h>
#include <glib.h>
#include <syslog.h>
+#include <limits.h>
#include "types.h"
#ifdef HAVE_NUMA_H
@@ -40,7 +41,6 @@ void dump_tree(void);
void activate_mappings(void);
void account_for_nic_stats(void);
-void check_power_mode(void);
void clear_cpu_tree(void);
void pci_numa_scan(void);
@@ -64,10 +64,11 @@ enum hp_e {
extern int debug_mode;
extern int one_shot_mode;
extern int power_mode;
-extern int need_cpu_rescan;
+extern int need_rescan;
extern enum hp_e hint_policy;
extern unsigned long long cycle_count;
extern unsigned long power_thresh;
+extern char *banscript;
/*
* Numa node access routines
@@ -103,10 +104,11 @@ extern int get_cpu_count(void);
*/
extern void rebuild_irq_db(void);
extern void free_irq_db(void);
+extern void add_banned_irq(int irq);
extern void for_each_irq(GList *list, void (*cb)(struct irq_info *info, void *data), void *data);
extern struct irq_info *get_irq_info(int irq);
extern void migrate_irq(GList **from, GList **to, struct irq_info *info);
-extern struct irq_info *add_misc_irq(int irq);
+extern struct irq_info *add_new_irq(int irq);
#define irq_numa_node(irq) ((irq)->numa_node)
diff --git a/irqlist.c b/irqlist.c
index c29ee84..2523173 100644
--- a/irqlist.c
+++ b/irqlist.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -45,6 +46,7 @@ struct load_balance_info {
unsigned int num_within;
unsigned int num_over;
unsigned int num_under;
+ unsigned int num_powersave;
struct topo_obj *powersave;
};
@@ -106,13 +108,16 @@ static void migrate_overloaded_irqs(struct topo_obj *obj, void *data)
struct load_balance_info *info = data;
int deviation;
+ if (obj->powersave_mode)
+ info->num_powersave++;
+
/*
* Don't rebalance irqs on objects whos load is below the average
*/
if (obj->load <= info->avg_load) {
if ((obj->load + info->std_deviation) <= info->avg_load) {
info->num_under++;
- if (!info->powersave)
+ if (power_thresh != ULONG_MAX && !info->powersave)
if (!obj->powersave_mode)
info->powersave = obj;
} else
@@ -172,13 +177,13 @@ void update_migration_status(void)
{
struct load_balance_info info;
find_overloaded_objs(cpus, info);
- if (cycle_count > 5) {
+ if (power_thresh != ULONG_MAX && cycle_count > 5) {
if (!info.num_over && (info.num_under >= power_thresh) && info.powersave) {
syslog(LOG_INFO, "cpu %d entering powersave mode\n", info.powersave->number);
info.powersave->powersave_mode = 1;
if (g_list_length(info.powersave->interrupts) > 0)
for_each_irq(info.powersave->interrupts, force_irq_migration, NULL);
- } else if (info.num_over) {
+ } else if ((info.num_over) && (info.num_powersave)) {
syslog(LOG_INFO, "Load average increasing, re-enabling all cpus for irq balancing\n");
for_each_object(cpus, clear_powersave_mode, NULL);
}
diff --git a/m4/cap-ng.m4 b/m4/cap-ng.m4
deleted file mode 100644
index 0024edc..0000000
--- a/m4/cap-ng.m4
+++ /dev/null
@@ -1,40 +0,0 @@
-# libcap-ng.m4 - Checks for the libcap-ng support
-# Copyright (c) 2009 Steve Grubb sgrubb@redhat.com
-#
-AC_DEFUN([LIBCAP_NG_PATH],
-[
- AC_ARG_WITH(libcap-ng,
- [ --with-libcap-ng=[auto/yes/no] Add Libcap-ng support [default=auto]],,
- with_libcap_ng=auto)
-
- # Check for Libcap-ng API
- #
- # libcap-ng detection
-
- if test x$with_libcap_ng = xno ; then
- have_libcap_ng=no;
- else
- # Start by checking for header file
- AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no)
-
- # See if we have libcap-ng library
- AC_CHECK_LIB(cap-ng, capng_clear,
- CAPNG_LDADD=-lcap-ng,)
-
- # Check results are usable
- if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then
- AC_MSG_ERROR(libcap-ng support was requested and the library was not found)
- fi
- if test x$CAPNG_LDADD != x -a $capng_headers = no ; then
- AC_MSG_ERROR(libcap-ng libraries found but headers are missing)
- fi
- fi
- AC_SUBST(CAPNG_LDADD)
- AC_MSG_CHECKING(whether to use libcap-ng)
- if test x$CAPNG_LDADD != x ; then
- AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support])
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(no)
- fi
-])
diff --git a/misc/irqbalance.env b/misc/irqbalance.env
new file mode 100644
index 0000000..bd87e3d
--- /dev/null
+++ b/misc/irqbalance.env
@@ -0,0 +1,26 @@
+# irqbalance is a daemon process that distributes interrupts across
+# CPUS on SMP systems. The default is to rebalance once every 10
+# seconds. This is the environment file that is specified to systemd via the
+# EnvironmentFile key in the service unit file (or via whatever method the init
+# system you're using has.
+#
+# ONESHOT=yes
+# after starting, wait for a minute, then look at the interrupt
+# load and balance it once; after balancing exit and do not change
+# it again.
+#IRQBALANCE_ONESHOT=
+
+#
+# IRQBALANCE_BANNED_CPUS
+# 64 bit bitmask which allows you to indicate which cpu's should
+# be skipped when reblancing irqs. Cpu numbers which have their
+# corresponding bits set to one in this mask will not have any
+# irq's assigned to them on rebalance
+#
+#IRQBALANCE_BANNED_CPUS=
+
+#
+# IRQBALANCE_ARGS
+# append any args here to the irqbalance daemon as documented in the man page
+#
+#IRQBALANCE_ARGS=
diff --git a/misc/irqbalance.service b/misc/irqbalance.service
index f349616..3139a83 100644
--- a/misc/irqbalance.service
+++ b/misc/irqbalance.service
@@ -3,9 +3,8 @@ Description=irqbalance daemon
After=syslog.target
[Service]
-EnvironmentFile=/etc/sysconfig/irqbalance
-Type=forking
-ExecStart=/usr/sbin/irqbalance $ONESHOT
+EnvironmentFile=/path/to/irqbalance.env
+ExecStart=/usr/sbin/irqbalance --foreground $IRQBALANCE_ARGS
[Install]
WantedBy=multi-user.target
diff --git a/numa.c b/numa.c
index 710ed67..96703bd 100644
--- a/numa.c
+++ b/numa.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -106,11 +107,11 @@ void build_numa_node_list(void)
static void free_numa_node(gpointer data)
{
struct topo_obj *obj = data;
- if (data == &unspecified_node)
- return;
-
g_list_free(obj->children);
- free(data);
+ g_list_free(obj->interrupts);
+
+ if (data != &unspecified_node)
+ free(data);
}
void free_numa_node_list(void)
diff --git a/placement.c b/placement.c
index 108ccc9..1172849 100644
--- a/placement.c
+++ b/placement.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhoramn@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -48,7 +49,7 @@ static void find_best_object(struct topo_obj *d, void *data)
/*
* Don't consider the unspecified numa node here
*/
- if ((d->obj_type == OBJ_TYPE_NODE) && (d->number == -1))
+ if (numa_avail && (d->obj_type == OBJ_TYPE_NODE) && (d->number == -1))
return;
/*
diff --git a/powermode.c b/powermode.c
deleted file mode 100644
index 82ba490..0000000
--- a/powermode.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2006, Intel Corporation
- *
- * This file is part of irqbalance
- *
- * This program file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program in a file named COPYING; if not, write to the
- * Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA
- */
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <string.h>
-
-#include "irqbalance.h"
-
-
-void check_power_mode(void)
-{
-}
-
diff --git a/procinterrupts.c b/procinterrupts.c
index 4d3b07b..431fffa 100644
--- a/procinterrupts.c
+++ b/procinterrupts.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2006, Intel Corporation
+ * Copyright (C) 2012, Neil Horman <nhorman@tuxdriver.com>
*
* This file is part of irqbalance
*
@@ -32,6 +33,8 @@
#define LINESIZE 4096
+extern cpumask_t banned_cpus;
+
static int proc_int_has_msi = 0;
static int msi_found_in_sysfs = 0;
@@ -80,8 +83,12 @@ void parse_proc_interrupts(void)
c++;
number = strtoul(line, NULL, 10);
info = get_irq_info(number);
- if (!info)
- info = add_misc_irq(number);
+ if (!info) {
+ if (!cycle_count)
+ continue;
+ need_rescan = 1;
+ info = add_new_irq(number);
+ }
count = 0;
cpunr = 0;
@@ -97,7 +104,7 @@ void parse_proc_interrupts(void)
cpunr++;
}
if (cpunr != core_count)
- need_cpu_rescan = 1;
+ need_rescan = 1;
info->last_irq_count = info->irq_count;
info->irq_count = count;
@@ -217,6 +224,9 @@ void parse_proc_stat(void)
cpunr = strtoul(&line[3], NULL, 10);
+ if (cpu_isset(cpunr, banned_cpus))
+ continue;
+
rc = sscanf(line, "%*s %*d %*d %*d %*d %*d %d %d", &irq_load, &softirq_load);
if (rc < 2)
break;