irqbalance/numa.c
Neil Horman a81cd26ab4 Fix segfault on non-numa enabled systems
If a system doesn't support numa, we have an emtpty top level of the balancing
tree (and we get a null dir pointer in build_numa_nodes to boot).  Fix this by
checking for that null condition and adding the unspecified numa node to the
list of all numa nodes.

See https://bugzilla.redhat.com/show_bug.cgi?id=746159 for details

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
2011-10-17 14:32:44 -04:00

174 lines
3.8 KiB
C

/*
* 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
*/
/*
* This file tries to map numa affinity of pci devices to their interrupts
* In addition the PCI class information is used to refine the classification
* of interrupt sources
*/
#include "config.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include "irqbalance.h"
#define SYSFS_NODE_PATH "/sys/devices/system/node"
GList *numa_nodes = NULL;
struct topo_obj unspecified_node = {
.load = 0,
.number = -1,
.obj_type = OBJ_TYPE_NODE,
.mask = CPU_MASK_ALL,
.interrupts = NULL,
.children = NULL,
.parent = NULL,
.obj_type_list = &numa_nodes,
};
static void add_one_node(const char *nodename)
{
char *path = alloca(strlen(SYSFS_NODE_PATH) + strlen(nodename) + 1);
struct topo_obj *new;
char *cpustr;
FILE *f;
if (!path)
return;
new = calloc(1, sizeof(struct topo_obj));
if (!new)
return;
sprintf(path, "%s/%s/cpumap", SYSFS_NODE_PATH, nodename);
f = fopen(path, "r");
if (ferror(f)) {
cpus_clear(new->mask);
} else {
fscanf(f, "%as", &cpustr);
if (!cpustr) {
cpus_clear(new->mask);
} else {
cpumask_parse_user(cpustr, strlen(cpustr), new->mask);
free(cpustr);
}
}
new->obj_type = OBJ_TYPE_NODE;
new->number = strtoul(&nodename[4], NULL, 10);
new->obj_type_list = &numa_nodes;
numa_nodes = g_list_append(numa_nodes, new);
}
void build_numa_node_list(void)
{
DIR *dir = opendir(SYSFS_NODE_PATH);
struct dirent *entry;
/*
* Add the unspecified node
*/
numa_nodes = g_list_append(numa_nodes, &unspecified_node);
if (!dir)
return;
do {
entry = readdir(dir);
if (!entry)
break;
if ((entry->d_type == DT_DIR) && (strstr(entry->d_name, "node"))) {
add_one_node(entry->d_name);
}
} while (entry);
}
static void free_numa_node(gpointer data)
{
if (data == (void *)(&unspecified_node))
return;
free(data);
}
void free_numa_node_list(void)
{
g_list_free_full(numa_nodes, free_numa_node);
numa_nodes = NULL;
}
static gint compare_node(gconstpointer a, gconstpointer b)
{
const struct topo_obj *ai = a;
const struct topo_obj *bi = b;
return (ai->number == bi->number) ? 0 : 1;
}
void add_package_to_node(struct topo_obj *p, int nodeid)
{
struct topo_obj find, *node;
find.number = nodeid;
GList *entry;
find.number = nodeid;
entry = g_list_find_custom(numa_nodes, &find, compare_node);
if (!entry) {
if (debug_mode)
printf("Could not find numa node for node id %d\n", nodeid);
return;
}
node = entry->data;
if (!p->parent) {
node->children = g_list_append(node->children, p);
p->parent = node;
}
}
void dump_numa_node_info(struct topo_obj *d, void *unused __attribute__((unused)))
{
char buffer[4096];
printf("NUMA NODE NUMBER: %d\n", d->number);
cpumask_scnprintf(buffer, 4096, d->mask);
printf("LOCAL CPU MASK: %s\n", buffer);
printf("\n");
}
struct topo_obj *get_numa_node(int nodeid)
{
struct topo_obj find;
GList *entry;
if (nodeid == -1)
return &unspecified_node;
find.number = nodeid;
entry = g_list_find_custom(numa_nodes, &find, compare_node);
return entry ? entry->data : NULL;
}