-
Notifications
You must be signed in to change notification settings - Fork 139
/
activate.c
135 lines (120 loc) · 3.6 KB
/
activate.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* Copyright (C) 2006, Intel Corporation
* Copyright (C) 2012, Neil Horman <[email protected]>
*
* 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 contains the code to communicate a selected distribution / mapping
* of interrupts to the kernel.
*/
#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include "irqbalance.h"
static int check_affinity(struct irq_info *info, cpumask_t applied_mask)
{
cpumask_t current_mask;
char buf[PATH_MAX];
sprintf(buf, "/proc/irq/%i/smp_affinity", info->irq);
if (process_one_line(buf, get_mask_from_bitmap, ¤t_mask) < 0)
return 1;
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;
int errsave, ret;
cpumask_t applied_mask;
/*
* only activate mappings for irqs that have moved
*/
if (!info->moved)
return;
if (!info->assigned_obj)
return;
/* activate only online cpus, otherwise writing to procfs returns EOVERFLOW */
cpus_and(applied_mask, cpu_online_map, info->assigned_obj->mask);
/*
* Don't activate anything for which we have an invalid mask
*/
if (check_affinity(info, applied_mask)) {
info->moved = 0; /* nothing to do, mark as done */
return;
}
sprintf(buf, "/proc/irq/%i/smp_affinity", info->irq);
file = fopen(buf, "w");
errsave = errno;
if (!file)
goto error;
cpumask_scnprintf(buf, PATH_MAX, applied_mask);
ret = fprintf(file, "%s", buf);
errsave = errno;
if (ret >= 0 && fflush(file)) {
ret = -1;
errsave = errno;
}
if (fclose(file)) {
ret = -1;
errsave = errno;
}
if (ret < 0)
goto error;
info->moved = 0; /*migration is done*/
return;
error:
/* Use EPERM as the explaination for EIO */
errsave = (errsave == EIO) ? EPERM : errsave;
log(TO_ALL, LOG_WARNING,
"Cannot change IRQ %i affinity: %s\n",
info->irq, strerror(errsave));
switch (errsave) {
case EAGAIN: /* Interrupted by signal. */
case EBUSY: /* Affinity change already in progress. */
case EINVAL: /* IRQ would be bound to no CPU. */
case ERANGE: /* CPU in mask is offline. */
case ENOMEM: /* Kernel cannot allocate CPU mask. */
/* Do not blacklist the IRQ on transient errors. */
break;
case ENOSPC: /* Specified CPU APIC is full. */
if (info->assigned_obj->obj_type != OBJ_TYPE_CPU)
break;
if (info->assigned_obj->slots_left > 0)
info->assigned_obj->slots_left = -1;
else
/* Negative slots to count how many we need to free */
info->assigned_obj->slots_left--;
force_rebalance_irq(info, NULL);
break;
default:
/* Any other error is considered permanent. */
info->level = BALANCE_NONE;
info->moved = 0; /* migration impossible, mark as done */
log(TO_ALL, LOG_WARNING, "IRQ %i affinity is now unmanaged\n",
info->irq);
}
}
void activate_mappings(void)
{
for_each_irq(NULL, activate_mapping, NULL);
}