Commit | Line | Data |
---|---|---|
096102bd DG |
1 | /* |
2 | * Copyright (C) 2011 - David Goulet <dgoulet@efficios.com> | |
fbb9748b | 3 | * 2014 - Jan Glauber <jan.glauber@gmail.com> |
096102bd | 4 | * |
d14d33bf AM |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License, version 2 only, | |
7 | * as published by the Free Software Foundation. | |
096102bd | 8 | * |
d14d33bf AM |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
096102bd | 13 | * |
d14d33bf AM |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
096102bd DG |
17 | */ |
18 | ||
19 | #define _GNU_SOURCE | |
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <sys/wait.h> | |
23 | ||
24 | #include <common/common.h> | |
fbb9748b | 25 | #include <common/utils.h> |
096102bd DG |
26 | |
27 | #include "modprobe.h" | |
28 | #include "kern-modules.h" | |
29 | ||
ab57d7d3 JG |
30 | #define LTTNG_MOD_REQUIRED 1 |
31 | #define LTTNG_MOD_OPTIONAL 0 | |
32 | ||
33 | /* LTTng kernel tracer mandatory core modules list */ | |
34 | struct kern_modules_param kern_modules_control_core[] = { | |
35 | { "lttng-tracer" }, /* MUST be loaded first so keep at top */ | |
36 | { "lttng-lib-ring-buffer" }, | |
37 | { "lttng-ring-buffer-client-discard" }, | |
38 | { "lttng-ring-buffer-client-overwrite" }, | |
39 | { "lttng-ring-buffer-metadata-client" }, | |
40 | { "lttng-ring-buffer-client-mmap-discard" }, | |
41 | { "lttng-ring-buffer-client-mmap-overwrite" }, | |
42 | { "lttng-ring-buffer-metadata-mmap-client" }, | |
43 | }; | |
44 | ||
45 | /* LTTng kernel tracer optional base modules list */ | |
46 | struct kern_modules_param kern_modules_control_opt[] = { | |
47 | { "lttng-types" }, | |
48 | { "lttng-ftrace" }, | |
49 | { "lttng-kprobes" }, | |
50 | { "lttng-kretprobes" }, | |
3fa9646c JG |
51 | }; |
52 | ||
53 | /* LTTng kernel tracer probe modules list */ | |
fbb9748b | 54 | struct kern_modules_param kern_modules_probes_default[] = { |
ab57d7d3 JG |
55 | { "lttng-probe-asoc" }, |
56 | { "lttng-probe-block" }, | |
57 | { "lttng-probe-btrfs" }, | |
58 | { "lttng-probe-compaction" }, | |
59 | { "lttng-probe-ext3" }, | |
60 | { "lttng-probe-ext4" }, | |
61 | { "lttng-probe-gpio" }, | |
62 | { "lttng-probe-irq" }, | |
63 | { "lttng-probe-jbd" }, | |
64 | { "lttng-probe-jbd2" }, | |
65 | { "lttng-probe-kmem" }, | |
66 | { "lttng-probe-kvm" }, | |
67 | { "lttng-probe-kvm-x86" }, | |
68 | { "lttng-probe-kvm-x86-mmu" }, | |
69 | { "lttng-probe-lock" }, | |
70 | { "lttng-probe-module" }, | |
71 | { "lttng-probe-napi" }, | |
72 | { "lttng-probe-net" }, | |
73 | { "lttng-probe-power" }, | |
74 | { "lttng-probe-printk" }, | |
75 | { "lttng-probe-random" }, | |
76 | { "lttng-probe-rcu" }, | |
77 | { "lttng-probe-regmap" }, | |
78 | { "lttng-probe-regulator" }, | |
79 | { "lttng-probe-rpm" }, | |
80 | { "lttng-probe-sched" }, | |
81 | { "lttng-probe-scsi" }, | |
82 | { "lttng-probe-signal" }, | |
83 | { "lttng-probe-skb" }, | |
84 | { "lttng-probe-sock" }, | |
85 | { "lttng-probe-statedump" }, | |
86 | { "lttng-probe-sunrpc" }, | |
87 | { "lttng-probe-timer" }, | |
88 | { "lttng-probe-udp" }, | |
89 | { "lttng-probe-vmscan" }, | |
90 | { "lttng-probe-v4l2" }, | |
91 | { "lttng-probe-workqueue" }, | |
92 | { "lttng-probe-writeback" }, | |
096102bd DG |
93 | }; |
94 | ||
fbb9748b JG |
95 | /* dynamic probe modules list */ |
96 | static struct kern_modules_param *probes; | |
97 | static int nr_probes; | |
98 | ||
e23b81ed | 99 | void modprobe_remove_lttng(const struct kern_modules_param *modules, |
ab57d7d3 | 100 | int entries, int required) |
096102bd DG |
101 | { |
102 | int ret = 0, i; | |
103 | char modprobe[256]; | |
104 | ||
e23b81ed | 105 | for (i = entries - 1; i >= 0; i--) { |
096102bd DG |
106 | ret = snprintf(modprobe, sizeof(modprobe), |
107 | "/sbin/modprobe -r -q %s", | |
e23b81ed | 108 | modules[i].name); |
096102bd DG |
109 | if (ret < 0) { |
110 | PERROR("snprintf modprobe -r"); | |
ab57d7d3 | 111 | return; |
096102bd DG |
112 | } |
113 | modprobe[sizeof(modprobe) - 1] = '\0'; | |
114 | ret = system(modprobe); | |
115 | if (ret == -1) { | |
116 | ERR("Unable to launch modprobe -r for module %s", | |
ab57d7d3 JG |
117 | modules[i].name); |
118 | } else if (required && WEXITSTATUS(ret) != 0) { | |
096102bd | 119 | ERR("Unable to remove module %s", |
ab57d7d3 | 120 | modules[i].name); |
096102bd DG |
121 | } else { |
122 | DBG("Modprobe removal successful %s", | |
ab57d7d3 | 123 | modules[i].name); |
096102bd | 124 | } |
fbb9748b JG |
125 | if (probes) |
126 | free(probes[i].name); | |
096102bd | 127 | } |
e23b81ed JG |
128 | } |
129 | ||
130 | /* | |
131 | * Remove control kernel module(s) in reverse load order. | |
132 | */ | |
133 | void modprobe_remove_lttng_control(void) | |
134 | { | |
ab57d7d3 | 135 | modprobe_remove_lttng(kern_modules_control_opt, |
fbb9748b JG |
136 | ARRAY_SIZE(kern_modules_control_opt), |
137 | LTTNG_MOD_OPTIONAL); | |
ab57d7d3 | 138 | modprobe_remove_lttng(kern_modules_control_core, |
fbb9748b JG |
139 | ARRAY_SIZE(kern_modules_control_core), |
140 | LTTNG_MOD_REQUIRED); | |
096102bd DG |
141 | } |
142 | ||
143 | /* | |
144 | * Remove data kernel modules in reverse load order. | |
145 | */ | |
146 | void modprobe_remove_lttng_data(void) | |
147 | { | |
fbb9748b JG |
148 | if (probes) { |
149 | modprobe_remove_lttng(probes, nr_probes, LTTNG_MOD_OPTIONAL); | |
150 | free(probes); | |
151 | probes = NULL; | |
152 | } else | |
153 | modprobe_remove_lttng(kern_modules_probes_default, | |
154 | ARRAY_SIZE(kern_modules_probes_default), | |
155 | LTTNG_MOD_OPTIONAL); | |
096102bd DG |
156 | } |
157 | ||
158 | /* | |
159 | * Remove all kernel modules in reverse order. | |
160 | */ | |
161 | void modprobe_remove_lttng_all(void) | |
162 | { | |
163 | modprobe_remove_lttng_data(); | |
164 | modprobe_remove_lttng_control(); | |
165 | } | |
166 | ||
fbb9748b | 167 | static int modprobe_lttng(struct kern_modules_param *modules, |
ab57d7d3 | 168 | int entries, int required) |
096102bd DG |
169 | { |
170 | int ret = 0, i; | |
171 | char modprobe[256]; | |
172 | ||
e23b81ed | 173 | for (i = 0; i < entries; i++) { |
096102bd DG |
174 | ret = snprintf(modprobe, sizeof(modprobe), |
175 | "/sbin/modprobe %s%s", | |
ab57d7d3 | 176 | required ? "" : "-q ", |
e23b81ed | 177 | modules[i].name); |
096102bd DG |
178 | if (ret < 0) { |
179 | PERROR("snprintf modprobe"); | |
180 | goto error; | |
181 | } | |
182 | modprobe[sizeof(modprobe) - 1] = '\0'; | |
183 | ret = system(modprobe); | |
184 | if (ret == -1) { | |
185 | ERR("Unable to launch modprobe for module %s", | |
e23b81ed | 186 | modules[i].name); |
ab57d7d3 JG |
187 | } else if (required && WEXITSTATUS(ret) != 0) { |
188 | ERR("Unable to load module %s", modules[i].name); | |
096102bd | 189 | } else { |
ab57d7d3 | 190 | DBG("Modprobe successfully %s", modules[i].name); |
096102bd DG |
191 | } |
192 | } | |
193 | ||
194 | error: | |
195 | return ret; | |
196 | } | |
197 | ||
e23b81ed JG |
198 | /* |
199 | * Load control kernel module(s). | |
200 | */ | |
201 | int modprobe_lttng_control(void) | |
202 | { | |
ab57d7d3 JG |
203 | int ret; |
204 | ||
205 | ret = modprobe_lttng(kern_modules_control_core, | |
206 | ARRAY_SIZE(kern_modules_control_core), | |
207 | LTTNG_MOD_REQUIRED); | |
208 | if (ret != 0) | |
209 | return ret; | |
210 | ret = modprobe_lttng(kern_modules_control_opt, | |
fbb9748b JG |
211 | ARRAY_SIZE(kern_modules_control_opt), |
212 | LTTNG_MOD_OPTIONAL); | |
ab57d7d3 | 213 | return ret; |
e23b81ed | 214 | } |
ab57d7d3 | 215 | |
096102bd DG |
216 | /* |
217 | * Load data kernel module(s). | |
218 | */ | |
219 | int modprobe_lttng_data(void) | |
220 | { | |
fbb9748b JG |
221 | int i, ret; |
222 | int entries = ARRAY_SIZE(kern_modules_probes_default); | |
223 | char *list, *next; | |
224 | ||
225 | /* | |
226 | * First take command line option, if not available take environment | |
227 | * variable. | |
228 | */ | |
229 | if (kmod_probes_list) { | |
230 | list = kmod_probes_list; | |
231 | } else { | |
232 | list = utils_get_kmod_probes_list(); | |
233 | } | |
234 | /* The default is to load ALL probes */ | |
235 | if (!list) { | |
236 | return modprobe_lttng(kern_modules_probes_default, entries, | |
237 | LTTNG_MOD_OPTIONAL); | |
238 | } | |
239 | ||
240 | /* | |
241 | * A probe list is available, so use it. | |
242 | * The number of probes is limited by the number of probes in the | |
243 | * default list. | |
244 | */ | |
245 | probes = zmalloc(sizeof(struct kern_modules_param *) * entries); | |
246 | if (!probes) { | |
247 | PERROR("malloc probe list"); | |
248 | return -ENOMEM; | |
249 | } | |
250 | ||
251 | for (i = 0; i < entries; i++) { | |
252 | size_t name_len; | |
253 | ||
254 | next = strtok(list, ","); | |
255 | if (!next) { | |
256 | goto out; | |
257 | } | |
258 | list = NULL; | |
259 | ||
260 | /* filter leading spaces */ | |
261 | while (*next == ' ') { | |
262 | next++; | |
263 | } | |
264 | ||
265 | /* Length 13 is "lttng-probe-" + \0 */ | |
266 | name_len = strlen(next) + 13; | |
267 | ||
268 | probes[i].name = zmalloc(name_len); | |
269 | if (!probes[i].name) { | |
270 | PERROR("malloc probe list"); | |
271 | return -ENOMEM; | |
272 | } | |
273 | ||
274 | ret = snprintf(probes[i].name, name_len, "lttng-probe-%s", next); | |
275 | if (ret < 0) { | |
276 | PERROR("snprintf modprobe name"); | |
277 | goto out; | |
278 | } | |
279 | } | |
280 | ||
281 | out: | |
282 | nr_probes = i; | |
283 | return modprobe_lttng(probes, nr_probes, LTTNG_MOD_OPTIONAL); | |
096102bd | 284 | } |